diff --git a/Gemfile b/Gemfile
index 8a6fa608..c4b87707 100644
--- a/Gemfile
+++ b/Gemfile
@@ -49,7 +49,7 @@ gem "activerecord-import", require: false
gem "httparty", "~> 0.21.0"
-
+gem "activestorage"
gem "country_select", "~> 8.0"
group :development do
diff --git a/Gemfile.lock b/Gemfile.lock
index 20110be5..b80fe450 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -567,6 +567,7 @@ PLATFORMS
DEPENDENCIES
activerecord-import
+ activestorage
annotate
aws-sdk-s3
axe-core-cucumber
diff --git a/app/controllers/teachers_controller.rb b/app/controllers/teachers_controller.rb
index 59fd16fe..aa83352d 100644
--- a/app/controllers/teachers_controller.rb
+++ b/app/controllers/teachers_controller.rb
@@ -92,6 +92,18 @@ def edit
@readonly = !is_admin?
end
+ def remove_file
+ file_attachment = @teacher.files.find(params[:file_id])
+ file_attachment.purge
+ flash[:notice] = "File was successfully removed"
+ redirect_back fallback_location: teacher_path(@teacher)
+ end
+
+ def upload_file
+ @teacher.files.attach(params[:file])
+ redirect_back fallback_location: teacher_path(@teacher), notice: "File was successfully uploaded"
+ end
+
def update
load_school
ordered_schools
@@ -117,6 +129,7 @@ def update
return
end
+ attach_new_files_if_any
send_email_if_application_status_changed_and_email_resend_enabled
if fail_to_update
@@ -255,9 +268,18 @@ def load_school
@school ||= School.find_or_create_by(**unique_school_params)
end
+ def attach_new_files_if_any
+ if params.dig(:teacher, :more_files).present?
+ params[:teacher][:more_files].each do |file|
+ @teacher.files.attach(file)
+ end
+ end
+ end
+
def teacher_params
teacher_attributes = [:first_name, :last_name, :school, :status, :snap,
- :more_info, :personal_website, :education_level, :school_id, languages: []]
+ :more_info, :personal_website, :education_level, :school_id, languages: [], files: [],
+ more_files: []]
admin_attributes = [:application_status, :request_reason, :skip_email]
teacher_attributes.push(*admin_attributes) if is_admin?
diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss
index bfecc5a6..5e5e2626 100644
--- a/app/javascript/styles/application.scss
+++ b/app/javascript/styles/application.scss
@@ -56,6 +56,20 @@ body {
}
}
+.btn-purple {
+ background-color: #8A2BE2; /* Light purple */
+}
+
+/* Style for the box around the file upload link */
+.box-link {
+ display: inline-block;
+ padding: 5px 10px;
+ height: 40px;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ background-color: #f9f9f9;
+}
+
.btn-blue {
background-color: #9dc0ee;
}
diff --git a/app/models/teacher.rb b/app/models/teacher.rb
index 265a48cf..b88e8951 100644
--- a/app/models/teacher.rb
+++ b/app/models/teacher.rb
@@ -36,6 +36,8 @@ class Teacher < ApplicationRecord
WORLD_LANGUAGES = [ "Afrikaans", "Albanian", "Arabic", "Armenian", "Basque", "Bengali", "Bulgarian", "Catalan", "Cambodian", "Chinese (Mandarin)", "Croatian", "Czech", "Danish", "Dutch", "English", "Estonian", "Fiji", "Finnish", "French", "Georgian", "German", "Greek", "Gujarati", "Hebrew", "Hindi", "Hungarian", "Icelandic", "Indonesian", "Irish", "Italian", "Japanese", "Javanese", "Korean", "Latin", "Latvian", "Lithuanian", "Macedonian", "Malay", "Malayalam", "Maltese", "Maori", "Marathi", "Mongolian", "Nepali", "Norwegian", "Persian", "Polish", "Portuguese", "Punjabi", "Quechua", "Romanian", "Russian", "Samoan", "Serbian", "Slovak", "Slovenian", "Spanish", "Swahili", "Swedish ", "Tamil", "Tatar", "Telugu", "Thai", "Tibetan", "Tonga", "Turkish", "Ukrainian", "Urdu", "Uzbek", "Vietnamese", "Welsh", "Xhosa" ].freeze
has_many :email_addresses, dependent: :destroy
+ has_many_attached :files
+ has_many_attached :more_files
accepts_nested_attributes_for :email_addresses, allow_destroy: true
validates :first_name, :last_name, :status, presence: true
@@ -83,6 +85,7 @@ class Teacher < ApplicationRecord
developer: 6,
excite: 7,
middle_school_bjc: 8,
+ home_school_bjc: 9
}
# Always add to the bottom of the list!
@@ -96,6 +99,7 @@ class Teacher < ApplicationRecord
"I am a BJC curriculum or tool developer.",
"I am teaching with the ExCITE project",
"I am teaching Middle School BJC.",
+ "I am teaching homeschool with the BJC curriculum."
].freeze
# From an admin perspective, we want to know if a teacher has any **meaningful** change
@@ -150,6 +154,7 @@ def self.status_options
:excite,
:teals_teacher,
:teals_volunteer,
+ :home_school_bjc,
:other,
:developer,
]
diff --git a/app/views/schools/_selectize_form.html.erb b/app/views/schools/_selectize_form.html.erb
index 894f8308..78459e4e 100644
--- a/app/views/schools/_selectize_form.html.erb
+++ b/app/views/schools/_selectize_form.html.erb
@@ -1,7 +1,7 @@
<%= f.label :name, "Search for your school or add a new one", class: "label-required", for: "school_selectize" %>
<%= f.select :name,
- options_for_select(@ordered_schools.collect(&:selectize_options)),
+ options_for_select( @ordered_schools.map(&:selectize_options)),
{prompt: "Enter the name or city of your school"},
{class: "select", id: "school_selectize" } %>
<%= javascript_pack_tag 'schools' %>
diff --git a/app/views/teachers/_files_display.html.erb b/app/views/teachers/_files_display.html.erb
new file mode 100644
index 00000000..09afda49
--- /dev/null
+++ b/app/views/teachers/_files_display.html.erb
@@ -0,0 +1,33 @@
+
+ <% if teacher.files.attached? %>
+ <% teacher.files.each do |file| %>
+
+ <%= link_to file.filename.to_s, rails_blob_path(file), target: "_blank", class: "box-link" %>
+ <% if show_delete_file %>
+ <%= button_to "❌", remove_file_teacher_path(teacher, file_id: file.id), method: :delete, data: { confirm: "Are you sure you want to remove this file?" }, style: "width: 40px;", class: "box-link" %>
+ <% end %>
+
+ <% end %>
+ <% else %>
+
No files attached yet.
+ <% end %>
+
+
+ <% if show_add_file %>
+ <%= form_tag(upload_file_teacher_path(teacher), method: :post, multipart: true, id: "file-upload-form") do %>
+ <%= file_field_tag :file, id: "file-upload-field", style: "display: none;" %>
+
+ <% end %>
+ <% end %>
+
+
+<% if show_add_file %>
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/teachers/_form.html.erb b/app/views/teachers/_form.html.erb
index 7c3cf65e..3ce16c0d 100644
--- a/app/views/teachers/_form.html.erb
+++ b/app/views/teachers/_form.html.erb
@@ -89,11 +89,35 @@ status ONLY IF the person viewing this page is an admin. %>
:status,
options_for_select(Teacher.status_options, teacher.status_before_type_cast),
{ include_blank: "Select an option" },
- { class: 'form-control', required: true, onchange: 'requireVolunteerHostTeacher();' }
+ { class: 'form-control', required: true, onchange: 'listenForStatusOptionChange();' }
) %>
<%= f.label :education_level, "What's your education level target?", class: "label-required" %>
@@ -117,37 +141,35 @@ status ONLY IF the person viewing this page is an admin. %>
multiple: true,
include_blank: "Select an option",
class: 'selectize', required: true
-) %>
+ ) %>
<%# If submission was successful, don't re-render the form. %>
<% if !flash[:success] %>
- <%= render 'form', teacher: @teacher, admin: @is_admin %>
+ <%= render 'form', teacher: @teacher, admin: @is_admin, is_new_teacher_page: true %>
<% end %>
diff --git a/config/application.rb b/config/application.rb
index 32af4818..b64c0e3b 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -14,6 +14,7 @@
# require "action_text/engine"
require "action_view/railtie"
# require "action_cable/engine"
+require "active_storage/engine"
# require "sprockets/railtie"
# require "rails/test_unit/railtie"
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 00bf3b70..039ad28e 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -70,5 +70,5 @@
# Store files locally
# config.active_storage.service = :amazon
- # config.active_storage.service = :local
+ config.active_storage.service = :local
end
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 2f98adf9..03961aa3 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -103,5 +103,5 @@
}
# Store files on Amazon S3. (Uncomment this when S3 is setup)
- # config.active_storage.service = :amazon
+ config.active_storage.service = :amazon
end
diff --git a/config/environments/test.rb b/config/environments/test.rb
index e3929085..3f9482e3 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -56,5 +56,5 @@
# config.action_view.annotate_rendered_view_with_filenames = true
# Store uploaded files on the local file system in a temporary directory.
- # config.active_storage.service = :test
+ config.active_storage.service = :test
end
diff --git a/config/routes.rb b/config/routes.rb
index 4c04a42c..0c99130a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -8,12 +8,14 @@
root to: "main#index"
resources :teachers do
+ post "upload_file", on: :member
resource :email_address, only: [:edit, :update, :create]
member do
post :resend_welcome_email
post :validate
post :deny
post :request_info
+ delete "remove_file", to: "teachers#remove_file"
end
collection { post :import }
end
diff --git a/db/seed_data.rb b/db/seed_data.rb
index ce084203..2c642b96 100644
--- a/db/seed_data.rb
+++ b/db/seed_data.rb
@@ -155,7 +155,7 @@ def self.create_schools
city: "Berkeley",
country: "US",
website: "https://bjc.berkeley.edu",
- state: "CA",
+ state: "CA"
)
end
diff --git a/features/admin.feature b/features/admin.feature
index 0322def0..e8e4867f 100644
--- a/features/admin.feature
+++ b/features/admin.feature
@@ -456,6 +456,44 @@ Feature: basic admin functionality
When I follow the first "Jane Doe" link
Then I should be on the merge preview page for Bobby into Jane
+ Scenario: Admin does not see uploaded files for teachers with non-homeschool status
+ Given the following schools exist:
+ | name | country | city | state | website | grade_level | school_type |
+ | UC Berkeley | US | Berkeley | CA | https://www.berkeley.edu | university | public |
+ And the following teachers exist:
+ | first_name | last_name | admin | primary_email | school | status |
+ | Jane | Doe | false | janedoe@berkeley.edu | UC Berkeley | I am using BJC as a resource, but not teaching with it. |
+ Given I am on the BJC home page
+ And I have an admin email
+ And I follow "Log In"
+ Then I can log in with Google
+ When I go to the show page for Jane Doe
+ Then I should not see "Supporting Files:"
+ When I go to the edit page for Jane Doe
+ Then I should not see "Supporting Files:"
+ And I should not see "Upload More Files:"
+
+ Scenario: Admin can edit files of a homeschool teacher on the teacher's show page
+ Given the following schools exist:
+ | name | country | city | state | website | grade_level | school_type |
+ | UC Berkeley | US | Berkeley | CA | https://www.berkeley.edu | university | public |
+ And the following teachers exist:
+ | first_name | last_name | admin | primary_email | school |
+ | Jane | Doe | false | janedoe@berkeley.edu | UC Berkeley |
+ Given I am on the BJC home page
+ And I have an admin email
+ And I follow "Log In"
+ Then I can log in with Google
+ Then I go to the edit page for Jane Doe
+ And I set my status as "I am teaching homeschool with the BJC curriculum."
+ And I press "Update"
+ Then I go to the show page for Jane Doe
+ When I attach the file with name "test_file.txt" on the show page
+ Then I see a confirmation "File was successfully uploaded"
+ When I click the first file deletion button
+ And I accept the popup alert
+ Then I see a confirmation "File was successfully removed"
+
# Scenario: Admin can import csv file. The loader should filter invalid record and create associate school.
# Given the following schools exist:
# | name | country | city | state | website |
diff --git a/features/form_submission.feature b/features/form_submission.feature
index 092e9a58..b3170c89 100644
--- a/features/form_submission.feature
+++ b/features/form_submission.feature
@@ -230,6 +230,15 @@ Feature: submit a form as a teacher
Then I should not see "Tags"
And I should not see "NCES ID"
+ Scenario: Upload file field changes visibility based on status option
+ Given I am on the BJC home page
+ And I set my status as "I am a TEALS volunteer, and am teaching the BJC curriculum."
+ Then the upload file field should be hidden
+ When I set my status as "I am teaching BJC as an AP CS Principles course."
+ Then the upload file field should be hidden
+ When I set my status as "I am teaching homeschool with the BJC curriculum."
+ Then the upload file field should be visible
+
Scenario: Teacher updates information and two emails are sent
Given the following schools exist:
| name | country | city | state | website | grade_level | school_type |
diff --git a/features/step_definitions/teacher_steps.rb b/features/step_definitions/teacher_steps.rb
index ed960e26..da84164c 100644
--- a/features/step_definitions/teacher_steps.rb
+++ b/features/step_definitions/teacher_steps.rb
@@ -123,3 +123,29 @@
expect(Teacher.find_by(teacher_params).blank?).to be true
end
end
+
+Then("the upload file field should be hidden") do
+ expect(page).to have_selector("#upload_file_field", visible: :hidden)
+end
+
+Then("the upload file field should be visible") do
+ expect(page).to have_selector("#upload_file_field", visible: :visible)
+end
+
+When("I attach the file with name {string} on the edit page") do |file_name|
+ page.execute_script("$('teacher_more_files').click()")
+ attach_file("teacher_more_files", Rails.root.join("spec/fixtures", file_name))
+end
+
+# Note: this is an admin-only action
+When("I attach the file with name {string} on the show page") do |file_name|
+ page.execute_script("$('label.btn.btn-primary.btn-purple.mr-2').click()"); # clicks the "Add a File" button
+ # Execute JavaScript to make the file input field temporarily visible
+ page.execute_script("$('#file-upload-field').css('display', 'block');")
+ attach_file("file-upload-field", Rails.root.join("spec/fixtures", file_name))
+ page.execute_script("$('#file-upload-field').css('display', 'none');")
+end
+
+When("I click the first file deletion button") do
+ first('input[data-confirm="Are you sure you want to remove this file?"]').click
+end
diff --git a/features/teacher.feature b/features/teacher.feature
index da7bab66..77e80ea4 100644
--- a/features/teacher.feature
+++ b/features/teacher.feature
@@ -144,6 +144,28 @@ Scenario: Logged in teacher with Not_Reviewed application status can update thei
And I should see "Edit Joe Mamoa"
And the "Snap! Username" field should contain "alonzo"
+Scenario: Homeschool teacher can add/view supporting files
+ Given I have a teacher Google email
+ And the following schools exist:
+ | name | country | city | state | website |
+ | UC Berkeley | US | Berkeley | CA | https://www.berkeley.edu |
+ And the following teachers exist:
+ | first_name | last_name | admin | primary_email | school |
+ | Joseph | Mamoa | false | testteacher@berkeley.edu | UC Berkeley |
+ And I am on the BJC home page
+ And I follow "Log In"
+ Then I can log in with Google
+ When I set my status as "I am teaching homeschool with the BJC curriculum."
+ Then I should see "No files attached yet."
+ When I attach the file with name "test_file.txt"
+ And I press "Update"
+ And I follow "test_file.txt"
+ Then I should see "test_file.txt"
+ When I attach the file with name "test_file2.txt"
+ And I press "Update"
+ Then I should see "test_file.txt"
+ And I should see "test_file2.txt"
+
Scenario: Logged in teacher can only edit their own information
Given the following schools exist:
| name | country | city | state | website |
diff --git a/spec/fixtures/test_file.txt b/spec/fixtures/test_file.txt
new file mode 100644
index 00000000..4c32e121
--- /dev/null
+++ b/spec/fixtures/test_file.txt
@@ -0,0 +1,2 @@
+This file only exists for the purposes of testing that
+attaching files works
\ No newline at end of file
diff --git a/spec/fixtures/test_file2.txt b/spec/fixtures/test_file2.txt
new file mode 100644
index 00000000..7fe27769
--- /dev/null
+++ b/spec/fixtures/test_file2.txt
@@ -0,0 +1,2 @@
+This file, likewise, only exists for the purposes of testing that
+attaching files works
\ No newline at end of file