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();' } ) %>
+ +<% if is_new_teacher_page %> +
+
+ <%= f.label :files, "Upload supporting files: " %> + <%= f.file_field :files, multiple: true, direct_upload: true %> +
+
+<% else %> + +
+
+ + <%= render 'files_display', teacher: @teacher, show_add_file: false, show_delete_file: false %> +
+
+ <%= f.label :more_files, "Upload More Files: " %> + <%= f.file_field :more_files, multiple: true, direct_upload: true %> +
+
+<% end %>
<%= 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 -) %> + ) %>
- -
- <%= f.label :more_info, "More Information", class: "label-required" %> - <%= f.text_area :more_info, placeholder: "I applied for access because...", - class: "form-control", required: true, rows: "2" %> + <%= f.label :more_info, "More Information", class: "label-required" %> + <%= f.text_area :more_info, placeholder: "I applied for access because...", + class: "form-control", required: true, rows: "2" %>
Please tell us why you need access.
- <%= f.hidden_field :school_id %> - + <%= f.hidden_field :school_id %> + -
- <%= form_with model: @teacher.school, local: true do |school| %> -

Your School

- <%= render 'schools/selectize_form', f: school %> - <%# NO END HERE -- NOTE BELOW %> -
- -<%= f.submit (f.object.new_record? ? 'Submit' : 'Update'), class: 'btn btn-primary' %> -<%# TWO ENDS MUST COME AFTER SUBMIT -- Rails bug??? %> +
+ <%= form_with model: @teacher.school, local: true do |school| %> +

Your School

+ <%= render 'schools/selectize_form', f: school %> +
+ + <%= f.submit (f.object.new_record? ? 'Submit' : 'Update'), class: 'btn btn-primary' %> + <% end %> <% end %> diff --git a/app/views/teachers/_teacher_info.html.erb b/app/views/teachers/_teacher_info.html.erb index 4f492a5d..6e243182 100644 --- a/app/views/teachers/_teacher_info.html.erb +++ b/app/views/teachers/_teacher_info.html.erb @@ -65,6 +65,12 @@ <%= teacher.display_application_status %> + <% if teacher.status_before_type_cast == 9 %> +
+
Supporting Files:
+ <%= render 'files_display', teacher: @teacher, show_add_file: true, show_delete_file: true %> +
+ <% end %>
Personal or Course Website:
diff --git a/app/views/teachers/edit.html.erb b/app/views/teachers/edit.html.erb index 13c95560..9dad1e74 100644 --- a/app/views/teachers/edit.html.erb +++ b/app/views/teachers/edit.html.erb @@ -12,5 +12,5 @@
- <%= render 'form', teacher: @teacher, admin: @is_admin %> + <%= render 'form', teacher: @teacher, admin: @is_admin, is_new_teacher_page: false %>
diff --git a/app/views/teachers/new.html.erb b/app/views/teachers/new.html.erb index 33816ef7..9714da4a 100644 --- a/app/views/teachers/new.html.erb +++ b/app/views/teachers/new.html.erb @@ -3,6 +3,6 @@
<%# 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