Skip to content

Commit

Permalink
Merge pull request #1327 from DFE-Digital/upload-documents-to-gdrive-…
Browse files Browse the repository at this point in the history
…rebased

Upload documents to google drive (UD3, UD6.1, UD6.2)
  • Loading branch information
cpjmcquillan authored Feb 18, 2020
2 parents 16820dc + 0a5bc83 commit e19d982
Show file tree
Hide file tree
Showing 31 changed files with 525 additions and 331 deletions.
65 changes: 64 additions & 1 deletion app/controllers/hiring_staff/vacancies/documents_controller.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
require 'google/apis/drive_v3'

class HiringStaff::Vacancies::DocumentsController < HiringStaff::Vacancies::ApplicationController
before_action :school, :redirect_unless_vacancy_session_id, only: %i[index create]
before_action :redirect_if_no_supporting_documents, only: %i[index create]
before_action :redirect_to_next_step_if_save_and_continue, only: :create

def index
@documents_form = DocumentsForm.new
@vacancy = Vacancy.find(session[:vacancy_attributes]['id'])
end

def create
@documents_form = DocumentsForm.new(documents_form_params)
@documents_form = DocumentsForm.new
@vacancy ||= school.vacancies.find(session_vacancy_id)
process_documents(documents_form_params).each do |document|
@vacancy.documents.create(document)
end
render :index
end

Expand All @@ -26,4 +33,60 @@ def redirect_if_no_supporting_documents
def redirect_to_next_step_if_save_and_continue
redirect_to application_details_school_job_path if params[:commit] == 'Save and continue'
end

def process_documents(params)
@file_size_limit = 10 # MB
documents_array = []
if params[:documents]&.any?
params[:documents].each do |document_params|
@errors = false
document_hash = upload_document(document_params)
unless @errors
documents_array << document_hash
end
end
end
documents_array
end

def upload_document(document_params)
document_upload = DocumentUpload.new(
upload_path: document_params.tempfile.path,
name: document_params.original_filename
)
if document_params.size / 1024.0 / 1024.0 > @file_size_limit
file_size_error(document_params.original_filename)
end
unless @errors
document_upload.upload
unless document_upload.safe_download
virus_error(document_params.original_filename)
end
create_document_hash(document_params, document_upload)
end
end

def file_size_error(filename)
@errors = true
@documents_form.errors.add(
:base, t('jobs.file_size_error_message', filename: filename, size_limit: @file_size_limit)
)
@documents_form.errors.add(:documents, t('jobs.file_input_error_message'))
end

def virus_error(filename)
@errors = true
@documents_form.errors.add(:base, t('jobs.file_virus_error_message', filename: filename))
@documents_form.errors.add(:documents, t('jobs.file_input_error_message'))
end

def create_document_hash(params, upload)
{
name: params.original_filename,
size: Integer(params.size),
content_type: params.content_type,
download_url: upload.uploaded.web_content_link,
google_drive_id: upload.uploaded.id
}
end
end
4 changes: 3 additions & 1 deletion app/form_models/vacancy_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ class VacancyForm
delegate :save, to: :vacancy

def initialize(params = {})
@vacancy = Vacancy.new(params.except(:expiry_time_hh, :expiry_time_mm, :expiry_time_meridiem))
@vacancy = Vacancy.new(
params.except(:documents_attributes, :expiry_time_hh, :expiry_time_mm, :expiry_time_meridiem)
)
end

def school
Expand Down
2 changes: 1 addition & 1 deletion app/frontend/packs/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import 'src/removeCommaFromNumber';
import 'src/shareUrl';
import 'src/sortJobList';
import 'src/submitFeedback';
import 'src/vacancyShow';
import 'src/uploadDocuments';
import 'src/vacancyShow';

import { initAll } from 'govuk-frontend';

Expand Down
74 changes: 62 additions & 12 deletions app/frontend/src/uploadDocuments.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,68 @@ document.addEventListener('DOMContentLoaded', function() {
const inputFileUpload = document.getElementsByClassName('govuk-file-upload')[0];
const selectFileButton = document.getElementsByClassName('govuk-button--secondary')[0];
const uploadFileButton = document.getElementsByClassName('govuk-button--secondary')[1];
const saveContinueButton = document.getElementsByName('commit')[1];

selectFileButton.addEventListener('click', function(e) {
e.preventDefault();

inputFileUpload.click();
});
if (inputFileUpload && selectFileButton && uploadFileButton && saveContinueButton) {
selectFileButton.addEventListener('click', function(e) {
e.preventDefault();
inputFileUpload.click();
});

inputFileUpload.addEventListener('change', function(e) {
saveContinueButton.disabled = true;
injectDocumentsTable(inputFileUpload);
inputFileUpload.form.submit();
});

inputFileUpload.classList.add('display-none');
uploadFileButton.classList.add('display-none');
selectFileButton.classList.remove('display-none');
}
});

inputFileUpload.addEventListener('change', function(e) {
inputFileUpload.form.submit();
});
injectDocumentsTable = function(documentsInput) {
const tableHTML = " \
<table class='govuk-table'> \
<thead class='govuk-table__head'> \
<tr class='govuk-table__row'> \
<th class='govuk-table__header'>File name</> \
<th class='govuk-table__header'>Status</> \
<th class='govuk-table__header'>File size</> \
<th class='govuk-table__header'>Action</> \
</tr> \
</thead> \
<tbody id='table-body' class='govuk-table__body'> \
</tbody> \
</table> \
"
const noFilesElement = document.getElementById('no-files');
const filesList = documentsInput.files;

inputFileUpload.classList.add('display-none');
uploadFileButton.classList.add('display-none');
selectFileButton.classList.remove('display-none');
});
if (filesList && filesList.length) {
if (noFilesElement) {
noFilesElement.insertAdjacentHTML("beforebegin", tableHTML);
noFilesElement.remove();
}
for (let i = 0; i < filesList.length; i++) {
const rowHTML = " \
<tr class='govuk-table__row'> \
<td class='govuk-table__cell' scope='row'>" +
filesList[i].name +
"</td> \
<td class='govuk-table__cell'>" +
"Uploading&nbsp;&nbsp;" + "<div class='upload-progress'><div></div><div></div><div></div><div></div></div>" +
"</td> \
<td class='govuk-table__cell' scope='row'>" +
(filesList[i].size / 1024.0 / 1024.0).toFixed(2) + " MB" +
"</td> \
<td class='govuk-table__cell' scope='row'>" +
"<a href='#' class='govuk-link govuk-link--no-visited-state'>Cancel</a>" +
"</td> \
</tr> \
"
const tableBody = document.getElementById('table-body');
tableBody.insertAdjacentHTML("beforeend", rowHTML);
}
}
}
38 changes: 37 additions & 1 deletion app/frontend/styles/components/upload-documents.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,43 @@
.upload-group .govuk-button {
#file-upload {
margin-bottom: 0;
}

.hidden-input {
display: none;
}

.upload-progress {
display: inline-block;
position: relative;
width: 18px;
height: 18px;
}
.upload-progress div {
box-sizing: border-box;
display: block;
position: absolute;
width: 18px;
height: 18px;
margin: 0px;
border: 3px solid green;
border-radius: 50%;
animation: spin 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: green transparent transparent transparent;
}
.upload-progress div:nth-child(1) {
animation-delay: -0.45s;
}
.upload-progress div:nth-child(2) {
animation-delay: -0.3s;
}
.upload-progress div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
4 changes: 4 additions & 0 deletions app/models/document.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Document < ApplicationRecord
belongs_to :vacancy
validates :name, :size, :content_type, :download_url, :google_drive_id, presence: true
end
4 changes: 2 additions & 2 deletions app/models/vacancy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ class Vacancy < ApplicationRecord
extend FriendlyId
extend ArrayEnum

attr_accessor :documents

friendly_id :slug_candidates, use: %w[slugged history]

enum status: { published: 0, draft: 1, trashed: 2 }
Expand Down Expand Up @@ -122,6 +120,8 @@ class Vacancy < ApplicationRecord

has_one :publish_feedback, class_name: 'VacancyPublishFeedback'

has_many :documents

delegate :name, to: :school, prefix: true, allow_nil: false
delegate :geolocation, to: :school, prefix: true, allow_nil: true

Expand Down
52 changes: 52 additions & 0 deletions app/services/document_upload.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require 'google/apis/drive_v3'

class DocumentUpload
class MissingUploadPath < StandardError; end
attr_accessor :drive_service, :upload_path, :name, :uploaded, :safe_download

def initialize(opts = {})
raise MissingUploadPath if opts[:upload_path].nil?
self.upload_path = opts[:upload_path]
self.name = opts[:name]
self.drive_service = Google::Apis::DriveV3::DriveService.new
end

def upload
upload_hiring_staff_document
set_public_permission_on_document
google_drive_virus_check
end

def upload_hiring_staff_document
self.uploaded = drive_service.create_file(
{ alt: 'media', name: name },
fields: 'id, web_view_link, web_content_link, mime_type',
upload_source: upload_path
)
end

def set_public_permission_on_document
drive_service.create_permission(
uploaded.id,
Google::Apis::DriveV3::Permission.new(type: 'anyone', role: 'reader')
)
end

def google_drive_virus_check
download_path = "#{uploaded.id}"
begin
drive_service.get_file(
uploaded.id,
acknowledge_abuse: false,
download_dest: download_path
)
rescue Google::Apis::ClientError
drive_service.delete_file(uploaded.id)
self.safe_download = false
else
self.safe_download = true
ensure
File.delete(download_path) if File.exist?(download_path)
end
end
end
45 changes: 0 additions & 45 deletions app/views/hiring_staff/documents/edit.html.erb

This file was deleted.

Loading

0 comments on commit e19d982

Please sign in to comment.