Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.

Commit a3d42d8

Browse files
committed
Merge pull request #822 from appirio-tech/feature/filestack-int
Feature/filestack int
2 parents de70a96 + 755337a commit a3d42d8

13 files changed

+385
-76
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*eslint no-undef:0*/
2+
import angular from 'angular'
3+
4+
describe('Topcoder File Input Directive', function() {
5+
var scope, element, isolateScope, fileInput
6+
7+
beforeEach(function() {
8+
bard.appModule('topcoder')
9+
bard.inject(this, '$compile', '$rootScope', '$timeout')
10+
scope = $rootScope.$new()
11+
12+
var html = '' +
13+
'<form>' +
14+
'<tc-file-input ' +
15+
'label-text="Submission"' +
16+
'field-id="SUBMISSION_ZIP"' +
17+
'button-text="Add File"' +
18+
'file-type="zip"' +
19+
'placeholder="Attach all visible files as a single .zip file"' +
20+
'mandatory="true"' +
21+
'set-file-reference="vm.setFileReference(file, fieldId)"' +
22+
'ng-model="vm.submissionForm.submissionZip"' +
23+
' />' +
24+
'</form>'
25+
var form = angular.element(html)
26+
element = form.find('tc-file-input')
27+
$compile(form)(scope)
28+
scope.$digest()
29+
30+
isolateScope = element.isolateScope()
31+
})
32+
33+
beforeEach(function() {
34+
fileInput = $(element).find('.none')[0]
35+
})
36+
37+
afterEach(function() {
38+
scope.$destroy()
39+
fileInput = undefined
40+
})
41+
42+
bard.verifyNoOutstandingHttpRequests()
43+
44+
describe('selectFile', function() {
45+
it('triggers a click on the file input', function() {
46+
var mockClick = sinon.spy(fileInput, 'click')
47+
48+
isolateScope.selectFile()
49+
scope.$digest()
50+
51+
expect(mockClick).calledOnce
52+
})
53+
})
54+
55+
describe('a change event on the file input', function() {
56+
var fileNameInput, fileList, mockSetFileReference
57+
58+
beforeEach(function() {
59+
fileNameInput = $(element).find('input[type=text]')[0]
60+
fileList = {
61+
0: {
62+
name: 'test.zip',
63+
size: 50,
64+
type: 'application/zip'
65+
},
66+
length: 1,
67+
item: function (index) { return index }
68+
}
69+
70+
mockSetFileReference = sinon.spy(isolateScope, 'setFileReference')
71+
})
72+
73+
afterEach(function() {
74+
fileNameInput = undefined
75+
fileList = undefined
76+
mockSetFileReference = undefined
77+
})
78+
79+
it('sets the value of the fileNameInput with the name of the file', function() {
80+
$(fileInput).triggerHandler({
81+
type: 'change',
82+
target: { files: fileList }
83+
})
84+
85+
$timeout.flush()
86+
87+
expect(fileNameInput.value).to.equal('test.zip')
88+
})
89+
90+
describe('with a valid file', function() {
91+
beforeEach(function() {
92+
$(fileInput).triggerHandler({
93+
type: 'change',
94+
target: { files: fileList }
95+
})
96+
$timeout.flush()
97+
})
98+
99+
it('calls setFileReference', function() {
100+
expect(mockSetFileReference).calledOnce
101+
})
102+
103+
it('has ng-valid-filesize class', function() {
104+
expect($(fileInput).hasClass('ng-valid-filesize')).to.be.true
105+
})
106+
107+
it('has ng-valid-required class', function() {
108+
expect($(fileInput).hasClass('ng-valid-required')).to.be.true
109+
})
110+
111+
it('works with Windows file type application/x-zip', function(){
112+
fileList[0].type = 'application/x-zip'
113+
114+
$(fileInput).triggerHandler({
115+
type: 'change',
116+
target: { files: fileList }
117+
})
118+
119+
$timeout.flush()
120+
121+
expect(mockSetFileReference).called
122+
expect($(fileInput).hasClass('ng-valid-filesize')).to.be.true
123+
expect($(fileInput).hasClass('ng-valid-required')).to.be.true
124+
})
125+
126+
it('works with Windows file type application/x-zip-compressed', function(){
127+
fileList[0].type = 'application/x-zip-compressed'
128+
129+
$(fileInput).triggerHandler({
130+
type: 'change',
131+
target: { files: fileList }
132+
})
133+
134+
$timeout.flush()
135+
136+
expect(mockSetFileReference).called
137+
expect($(fileInput).hasClass('ng-valid-filesize')).to.be.true
138+
expect($(fileInput).hasClass('ng-valid-required')).to.be.true
139+
})
140+
})
141+
142+
describe('with a file type that\'s not in the list of fileTypes given to the directive', function() {
143+
beforeEach(function() {
144+
fileList[0].type = 'image/png'
145+
146+
$(fileInput).triggerHandler({
147+
type: 'change',
148+
target: { files: fileList }
149+
})
150+
151+
$timeout.flush()
152+
})
153+
154+
it('does not call setFileReference', function() {
155+
expect(mockSetFileReference).not.calledOnce
156+
})
157+
158+
it('has ng-touched and ng-invalid-required classes', function() {
159+
expect($(fileInput).hasClass('ng-invalid-required')).to.be.true
160+
expect($(fileInput).hasClass('ng-touched')).to.be.true
161+
})
162+
})
163+
164+
describe('with a file extension that is not in the list of fileTypes given to the directive', function() {
165+
beforeEach(function() {
166+
fileList[0].name = 'submission.zip.jpg'
167+
168+
$(fileInput).triggerHandler({
169+
type: 'change',
170+
target: { files: fileList }
171+
})
172+
173+
$timeout.flush()
174+
})
175+
176+
it('does not call setFileReference', function() {
177+
expect(mockSetFileReference).not.calledOnce
178+
})
179+
180+
it('has ng-touched and ng-invalid-required classes', function() {
181+
expect($(fileInput).hasClass('ng-invalid-required')).to.be.true
182+
expect($(fileInput).hasClass('ng-touched')).to.be.true
183+
})
184+
})
185+
186+
describe('with a file that\'s greater than 500MB', function() {
187+
beforeEach(function() {
188+
fileList[0].size = 524288001
189+
190+
$(fileInput).triggerHandler({
191+
type: 'change',
192+
target: { files: fileList }
193+
})
194+
195+
$timeout.flush()
196+
})
197+
198+
it('does not call setFileReference', function() {
199+
expect(mockSetFileReference).not.calledOnce
200+
})
201+
202+
it('has ng-touched and ng-invalid-filesize classes', function() {
203+
expect($(fileInput).hasClass('ng-invalid-filesize')).to.be.true
204+
expect($(fileInput).hasClass('ng-touched')).to.be.true
205+
})
206+
})
207+
})
208+
})
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import angular from 'angular'
2+
import _ from 'lodash'
3+
4+
(function() {
5+
'use strict'
6+
7+
angular.module('tcUIComponents').directive('tcFpFileInput', ['$rootScope', 'CONSTANTS', 'logger', 'UserService', 'filepickerService', tcFPFileInput])
8+
9+
function tcFPFileInput($rootScope, CONSTANTS, logger, UserService, filepickerService) {
10+
return {
11+
restrict: 'E',
12+
require: '^form',
13+
template: require('./tc-fp-file-input')(),
14+
scope: {
15+
labelText: '@',
16+
fieldId: '@',
17+
placeholder: '@',
18+
fileType: '@',
19+
showFileType: '=',
20+
mandatory: '=',
21+
maxFileSize: '@',
22+
fpServices: '@',
23+
buttonText: '@',
24+
setFileReference: '&',
25+
ngModel: '='
26+
},
27+
link: function(scope, element, attrs, formController) {
28+
// set filePath
29+
var userId = parseInt(UserService.getUserIdentity().userId)
30+
scope.filePath = scope.fieldId + '/'
31+
if (scope.fieldId.indexOf('ZIP') > -1) {
32+
scope.filePath += _.join([userId, scope.fieldId, (new Date()).valueOf()], '-') + '.zip'
33+
}
34+
// set extensions
35+
if (scope.fieldId.indexOf('ZIP') > -1) {
36+
scope.extensions = ".zip"
37+
} else if (scope.fieldId.indexOf('DESIGN_COVER') > -1) {
38+
scope.extensions = ".png,.jpeg,.jpg,.bmp"
39+
}
40+
41+
// set default services
42+
scope.fpServices = scope.fpServices || "COMPUTER,GOOGLE_DRIVE,BOX,DROPBOX"
43+
scope.fpContainer = CONSTANTS.FILE_PICKER_SUBMISSION_CONTAINER_NAME || 'submission-staging-dev'
44+
45+
// set max size
46+
scope.maxSize = 500*1024*1024
47+
48+
var key, value;
49+
/*
50+
*pass original event
51+
*/
52+
element.bind('change', function(event) {
53+
event.preventDefault()
54+
scope.onSuccess(event.originalEvent || event);
55+
$rootScope.$apply()
56+
});
57+
element = element.length ? element[0] : element;
58+
for (key in attrs.$attr){
59+
value = attrs.$attr[key]
60+
element.setAttribute(value, attrs[key])
61+
}
62+
filepickerService.constructWidget(element)
63+
64+
scope.onSuccess = function (event) {
65+
debugger
66+
var fpFile = event.fpfile
67+
var _file = {
68+
name: scope.filename || fpFile.filename,
69+
container: fpFile.container || scope.fpContainer,
70+
path: fpFile.key,
71+
size: fpFile.size,
72+
mimetype: fpFile.mimetype
73+
}
74+
scope.ngModel = _file
75+
scope.setFileReference({file: _file, fieldId: scope.fieldId})
76+
}
77+
}
78+
}
79+
}
80+
})()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.tc-file-field__label
2+
label.tc-label {{labelText}}
3+
span.lowercase(ng-if="showFileType") {{ ' *(.' + fileType + ')'}}
4+
5+
.tc-file-field__inputs
6+
.tc-label__wrapper
7+
span.tc-label__asterisk.lowercase(ng-if="mandatory") #[span *]mandatory
8+
input.tc-file-field__input(
9+
type="filepicker-dragdrop",
10+
data-fp-maxSize="{{maxSize}}",
11+
data-fp-button-class="tc-btn",
12+
data-fp-services="{{fpServices}}",
13+
data-fp-multiple="false",
14+
data-fp-extensions="{{extensions}}",
15+
data-fp-store-location="s3",
16+
data-fp-store-container="{{fpContainer}}",
17+
data-fp-store-path="{{filePath}}",
18+
on-success="onFileSeleted(event.fpfile)"
19+
)

app/services/submissions.service.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,25 @@ import angular from 'angular'
1111
var api = ApiService.getApiServiceProvider('SUBMISSIONS')
1212

1313
var service = {
14-
getPresignedURL: getPresignedURL,
15-
uploadSubmissionFileToS3: uploadSubmissionFileToS3,
16-
updateSubmissionStatus: updateSubmissionStatus,
17-
recordCompletedSubmission: recordCompletedSubmission
14+
startSubmission: startSubmission,
15+
processSubmission: processSubmission
16+
// uploadSubmissionFileToS3: uploadSubmissionFileToS3,
17+
// updateSubmissionStatus: updateSubmissionStatus,
18+
// recordCompletedSubmission: recordCompletedSubmission
1819
}
1920

2021
return service
2122

22-
function getPresignedURL(body, files, progressCallback) {
23+
function startSubmission(body, progressCallback) {
2324
return api.all('submissions').customPOST(body)
2425
.then(function(response) {
25-
progressCallback.call(progressCallback, 'PREPARE', 100)
26+
//progressCallback.call(progressCallback, 'PREPARE', 100)
2627

27-
uploadSubmissionFileToS3(response, response.data.files, files, progressCallback)
28+
// uploadSubmissionFileToS3(response, response.data.files, files, progressCallback)
29+
30+
console.log(response);
31+
32+
processSubmission(response, progressCallback);
2833
})
2934
.catch(function(err) {
3035
logger.error('Could not get presigned url', err)
@@ -35,6 +40,7 @@ import angular from 'angular'
3540
})
3641
}
3742

43+
/**
3844
function uploadSubmissionFileToS3(presignedURLResponse, filesWithPresignedURL, files, progressCallback) {
3945
4046
var promises = filesWithPresignedURL.map(function(fileWithPresignedURL) {
@@ -120,14 +126,17 @@ import angular from 'angular'
120126
progressCallback.call(progressCallback, 'ERROR', err)
121127
})
122128
}
129+
*/
123130

124-
function recordCompletedSubmission(body, progressCallback) {
131+
function processSubmission(body, progressCallback) {
125132
// Once all uploaded, make record and begin processing
126133
return api.one('submissions', body.id).customPOST(body, 'process')
127134
.then(function(response) {
128135
logger.info('Successfully made file record. Beginning processing')
129136

130137
progressCallback.call(progressCallback, 'FINISH', 100)
138+
139+
return response;
131140
})
132141
.catch(function(err) {
133142
logger.error('Could not start processing', err)

app/submissions/submissions.module.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ import angular from 'angular'
88
'tc.services',
99
'tcUIComponents',
1010
'toaster',
11-
'appirio-tech-ng-ui-components'
11+
'appirio-tech-ng-ui-components',
12+
'angular-filepicker'
1213
]
1314

1415
angular.module('tc.submissions', dependencies)
16+
.config(['filepickerProvider', 'CONSTANTS',
17+
function (filepickerProvider, CONSTANTS) {
18+
filepickerProvider.setKey(CONSTANTS.FILE_PICKER_API_KEY || 'AzFINuQoqTmqw0QEoaw9az')
19+
}
20+
])
1521

1622
})()

0 commit comments

Comments
 (0)