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

Staging release #718

Merged
merged 27 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
23a5aaa
Enable `pgcrypto` PSQL extension
Lubosky Aug 21, 2024
29f2896
Add `ProtectedFile` model w/ migrations
Lubosky Aug 21, 2024
3c753c2
Add `NominationStatsSearch` service to get grouped data for report
Lubosky Aug 21, 2024
d7b5a60
Views & policies for nomination statistics
Lubosky Aug 21, 2024
316aa5c
Add mailer to send requested CSV file
Lubosky Aug 21, 2024
21328d0
Merge pull request #711 from bitzesty/nomination-statistics-report
TheDancingClown Aug 22, 2024
410a097
Modify support letter fields so each upload section is a new question
DaniBitZesty Aug 22, 2024
e4377e2
Extract question ref code into partial so it only has to be mofified …
DaniBitZesty Aug 22, 2024
829f49c
Adjust centering & styling on statistics page
Lubosky Aug 22, 2024
ae51742
Switch to text layout for email sent to user
Lubosky Aug 22, 2024
6ff3e11
Update non-js views with new format for Letters of Support
DaniBitZesty Aug 22, 2024
1c4c572
Update how index is written
DaniBitZesty Aug 22, 2024
00e75c8
Use `LEFT JOIN` to get also not assigned lieutenancies
Lubosky Aug 22, 2024
dff782e
Merge pull request #712 from bitzesty/nomination-statistics-report-qa
TheDancingClown Aug 23, 2024
13651e3
chore: Update email layout and styling for nomination statistics report
TheDancingClown Aug 27, 2024
10810b4
chore: Use existing code for lieutenancy filter
TheDancingClown Aug 28, 2024
b153dcf
Non-js destroy action for support letter attachments
DaniBitZesty Aug 23, 2024
3c77bbe
JS remove support letter attachment feature
DaniBitZesty Aug 27, 2024
fab91b2
Merge pull request #713 from bitzesty/letters-of-support
DaniBitZesty Aug 28, 2024
90270c9
Fix validation on Letters of Support subquestions
DaniBitZesty Aug 28, 2024
ea2df1c
Merge pull request #715 from bitzesty/letters-of-support
DaniBitZesty Aug 28, 2024
bb762e9
Merge pull request #714 from bitzesty/statistics-table
TheDancingClown Aug 28, 2024
e30117c
- Remove validation for old letters of support question. This checks …
DaniBitZesty Aug 28, 2024
a263acf
Merge pull request #716 from bitzesty/letters-of-support
macool Aug 28, 2024
9bb0e70
- Show status of attachment when first uploaded.
DaniBitZesty Aug 29, 2024
f06a4a6
Remove random square bracket in icon link - causing deployment errors
DaniBitZesty Aug 29, 2024
9859107
Merge pull request #717 from bitzesty/letters-of-support
DaniBitZesty Aug 29, 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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ window.SupportLetters =

$(document).on 'change', '.js-trigger-autosave', debounce(SupportLetters.submit, 1000)

$(document).on 'click', '.js-remove-support-letter-attachment', (e) ->
e.preventDefault()
SupportLetters.removeFile($(this).closest('.govuk-form-group').find('input:first'), e)

new_item_init: (el) ->
SupportLetters.clean_up_system_tags(el)
SupportLetters.enable_item_fields_and_controls(el)
Expand All @@ -25,12 +29,14 @@ window.SupportLetters =

parent.find('.govuk-error-message').html('')
parent.find('.govuk-error-message').closest('.govuk-form-group').removeClass('govuk-form-group--error')

label = $('<p class="govuk-body support-letter-attachment-filename">' + filename + '</p>')

textContainer = parent.find('.support-letter-attachment-container')
textContainer.removeClass('govuk-!-display-none')
scanningText = '<p class="govuk-hint">(File uploaded and is being scanned for viruses. Preview available once the scan is complete.)</p>'
textContainer.prepend('<div class="support-letter-attachment-filename"><p class="govuk-body">' + filename + '</p>' + scanningText + '</div>')
hiddenInput = $("<input class='js-support-letter-attachment-id' type='hidden' name='#{$el.attr("name")}' value='#{data.result['id']}' />")

parent.append(label)
parent.append(hiddenInput)
parent.find('.js-support-letter-attachment').addClass('govuk-!-display-none')
SupportLetters.autosave()
SupportLetters.submit(e)

Expand Down Expand Up @@ -61,6 +67,15 @@ window.SupportLetters =
parent.find('input[type="hidden"]').remove()
parent.find('.support-letter-attachment-filename').remove()

removeFile: (el, e) ->
$el = $(el)
$el.val('')
$el.siblings('.js-support-letter-attachment-id').first().val('')
$el.siblings('.support-letter-attachment-container').addClass('govuk-!-display-none')
$el.removeClass('govuk-!-display-none')
SupportLetters.autosave()
SupportLetters.submit(e)

enable_item_fields_and_controls: (parent) ->
parent.find('.govuk-error-message').html('')
prefixed = parent.find('.js-system-tag').data('new-hidden-input-name')
Expand Down
21 changes: 7 additions & 14 deletions app/assets/javascripts/frontend/form-validation.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ window.FormValidation =
clearErrors: (container) ->
if container.closest(".question-financial").length > 0
container.closest("label").find(".govuk-error-message").empty()
else if container.closest('.question-block').data('answer').indexOf('address') > -1
else if container.closest('.question-block').data('answer') && container.closest('.question-block').data('answer').indexOf('address') > -1
container.closest(".govuk-form-group").find(".govuk-error-message").empty()
else
container.closest(".question-block").find(".govuk-error-message").empty()
Expand Down Expand Up @@ -56,6 +56,9 @@ window.FormValidation =
isCheckboxQuestion: (question) ->
question.find("input[type='checkbox']").length

isSupportLetterAttachment: (question) ->
question.find(".js-support-letter-attachment").length

toDate: (str) ->
moment(str, "DD/MM/YYYY")

Expand All @@ -81,6 +84,9 @@ window.FormValidation =
if @isCheckboxQuestion(question)
return question.find("input[type='checkbox']").filter(":checked").length

if @isSupportLetterAttachment(question)
return (question.find(".js-support-letter-attachment-id").val() || '').toString().trim().length

validateRequiredQuestion: (question) ->
# if it's a conditional question, but condition was not satisfied
conditional = true
Expand Down Expand Up @@ -352,13 +358,6 @@ window.FormValidation =
@addErrorMessage(question, errorMessage)
return

validateSupportLetters: (question) ->
lettersReceived = $(".js-support-letter-received").length
if lettersReceived < 2
@logThis(question, "validateSupportLetters", "Upload two letters of support")
@appendMessage(question, "Upload two letters of support")
@addErrorClass(question)

validateSelectionLimit: (question) ->
selection_limit = question.data("selection-limit")
current_selection_count = question.find("input[type=checkbox]:checked").length
Expand Down Expand Up @@ -455,11 +454,6 @@ window.FormValidation =
# console.log "validateDropBlockCondition"
@validateDropBlockCondition(question)

if question.hasClass("question-support-requests") ||
question.hasClass("question-support-uploads")
# console.log "validateSupportLetters"
@validateSupportLetters(question)

if question.hasClass("question-limited-selections")
@validateSelectionLimit(question)

Expand Down Expand Up @@ -489,7 +483,6 @@ window.FormValidation =
stepContainer.find(".govuk-form-group--error").removeClass("govuk-form-group--error")
stepContainer.find(".govuk-error-message").empty()
$(".steps-progress-bar .js-step-link[data-step='" + currentStep + "']").removeClass("step-errors")

for question in stepContainer.find(".question-block")
question = $(question)
@validateIndividualQuestion(question)
41 changes: 41 additions & 0 deletions app/assets/stylesheets/admin/tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,44 @@
[role="region"][aria-labelledby][tabindex]:focus {
outline: .1em solid rgba(0,0,0,.1);
}

.kavs-table {
border-top: 1px solid #b1b4b6;
border-bottom: 1px solid #b1b4b6;
width: max-content;

.text-center {
text-align: center;
}

thead {
background-color: #f2f2f2;

.govuk-table__header:last-child,
.govuk-table__cell:last-child,
.govuk-table__footer:last-child {
padding-right: 10px;
}
}

tfoot {
&.govuk-table__footer {
background-color: #f2f2f2;
font-weight: 700;
text-align: left;
}
}
}

.kavs-table__header--dense,
.kavs-table__cell--dense,
.kavs-table__footer--dense {
font-size: 1rem;
padding: 10px
}

.kavs-table__header--border-right,
.kavs-table__cell--border-right,
.kavs-table__footer--border-right {
border-right: 1px solid #b1b4b6;
}
5 changes: 5 additions & 0 deletions app/assets/stylesheets/frontend/forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,11 @@ input[type="file"] {
padding: 20px !important;
border: 2px solid #000 !important;

&.borderless {
border: 0 !important;
padding: 0 !important;
}

.lte-ie7 & {
display: inline;
width: 100%;
Expand Down
19 changes: 16 additions & 3 deletions app/assets/stylesheets/frontend/views/award_form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,28 @@
margin: 0.75em 0;
}

.support-letter-attachment-filename,
label > .visible-read-only,
.view-value {
margin-bottom: 10px;
font-weight: normal;
}

.support-letter-attachment-filename {
display: block;
.support-letter-attachment-container {
padding: 15px;
display: flex;
justify-content: space-between;
align-items: start;
background: $govuk-light-grey;

.js-remove-support-letter-attachment{
color: $govuk-red;
word-break: keep-all;
margin-top: 0 !important;
}

.non-js-remove-support-letter-attachment {
color: $govuk-red;
}
}

.view-only,
Expand Down
3 changes: 3 additions & 0 deletions app/controllers/admin/protected_files_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Admin::ProtectedFilesController < Admin::BaseController
include ProtectedFileMixin
end
101 changes: 101 additions & 0 deletions app/controllers/admin/statistics/nominations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
class Admin::Statistics::NominationsController < Admin::BaseController
def index
authorize :statistics, :index?

@search = NominationStatsSearch.new(FormAnswer.all).search(permitted_params)
end

def create
authorize :statistics, :send?

@search = NominationStatsSearch.new(FormAnswer.all).search(permitted_params)

data = generate_csv(@search.results)
file = current_admin.protected_files.create_from_raw_data(data, "nomination-statistics-export.csv")

Admin::Statistics::NominationMailer.notify(current_admin.id, file.id).deliver_now

redirect_to admin_statistics_nominations_path(search: permitted_params), success: "CSV with nomination statistics has been sent to #{current_admin.email}."
end

private

def permitted_params
params.fetch(:search, NominationStatsSearch.default_search).permit!
end

def generate_csv(data)
CSV.generate(encoding: "UTF-8", force_quotes: true) do |csv|
csv << csv_mapping.map { |m| m[:label] }
data.each do |row|
csv << csv_mapping.map do |m|
func = m[:method]
row[func]
end
end

csv << csv_mapping.map do |m|
func = m[:method]

if func == :ceremonial_county_name
"Total"
else
data.sum(&func)
end
end
end
end

def csv_mapping
[
{
label: "Lieutenancy",
method: :ceremonial_county_name
},
{
label: "Nominations submitted",
method: :submitted_count
},
{
label: "Eligiblity - Admin eligible",
method: :admin_eligible_count
},
{
label: "Eligiblity - Not eligible nominator",
method: :admin_not_eligible_nominator_count
},
{
label: "Eligiblity - Not eligible group",
method: :admin_not_eligible_group_count
},
{
label: "Eligiblity - Withdrawn",
method: :withdrawn_count
},
{
label: "Local Assessment - Not recommended",
method: :local_assessment_not_recommended_count
},
{
label: "Local Assessment - Recommended",
method: :local_assessment_recommended_count
},
{
label: "National Assessment - Not recommended",
method: :not_recommended_count
},
{
label: "National Assessment - Recommended",
method: :shortlisted_count
},
{
label: "Royal Approval - Awarded",
method: :awarded_count
},
{
label: "Total",
method: :total_count
}
]
end
end
13 changes: 13 additions & 0 deletions app/controllers/concerns/protected_file_mixin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module ProtectedFileMixin
extend ActiveSupport::Concern

def self.included(base)
base.skip_after_action :verify_authorized
end

def show
file = current_subject.protected_files.find(params[:id])
file.mark_as_downloaded!
redirect_to file.file.url, allow_other_host: true
end
end
29 changes: 29 additions & 0 deletions app/controllers/form/support_letter_attachments_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class Form::SupportLetterAttachmentsController < Form::BaseController
include FormAnswerSubmissionMixin
before_action :set_support_letter

def show; end

def destroy
attachment = SupportLetterAttachment.find(params[:id])
form_answer = attachment.form_answer

if attachment.destroy
updated_list = form_answer.document['supporter_letters_list'].reject { |letter| letter['letter_of_support'] == attachment.id }
form_answer.update(document: form_answer.document.merge(supporter_letters_list: updated_list))

flash[:notice] = 'Attachment successfully deleted.'
else
flash[:alert] = 'Failed to delete attachment.'
end

redirect_to form_form_answer_supporters_path(form_answer)
end

private

def set_support_letter
@support_letter = SupportLetter.find(params[:support_letter_id])
@form_answer = @support_letter.form_answer
end
end
2 changes: 1 addition & 1 deletion app/controllers/form/support_letters_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def add_support_letters_to_document!
h[:first_name] = support_letter.first_name
h[:last_name] = support_letter.last_name
h[:relationship_to_nominee] = support_letter.relationship_to_nominee
h[:letter_of_support] = support_letter.support_letter_attachment.id
h[:letter_of_support] = support_letter.support_letter_attachment&.id
end
end

Expand Down
12 changes: 12 additions & 0 deletions app/mailers/admin/statistics/nomination_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Admin::Statistics::NominationMailer < ApplicationMailer
layout "mailer"

def notify(identifier, file_identifier)
@admin = Admin.find(identifier)
@file = @admin.protected_files.find(file_identifier)

subject = "Nomination statistics export - King's Award for Voluntary Service"

view_mail ENV["GOV_UK_NOTIFY_API_TEMPLATE_ID"], to: @admin.email, subject: subject_with_env_prefix(subject)
end
end
1 change: 1 addition & 0 deletions app/models/admin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Admin < ApplicationRecord
validates :first_name, :last_name, presence: true

has_many :form_answer_attachments, as: :attachable
has_many :protected_files, as: :entity, dependent: :destroy

pg_search_scope :basic_search,
against: [
Expand Down
2 changes: 2 additions & 0 deletions app/models/assessor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class Assessor < ApplicationRecord
foreign_key: :sub_group,
primary_key: :sub_group

has_many :protected_files, as: :entity, dependent: :destroy

pg_search_scope :basic_search,
against: [
:first_name,
Expand Down
2 changes: 2 additions & 0 deletions app/models/group_leader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class GroupLeader < ApplicationRecord

belongs_to :form_answer, optional: true

has_many :protected_files, as: :entity, dependent: :destroy

scope :by_email, -> { order(:email) }
scope :confirmed, -> { where.not(confirmed_at: nil) }

Expand Down
Loading
Loading