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

Commit 39f8a4f

Browse files
author
Jenkins Continuous Integration Server
committed
Merge commit 'ff8c8e36ab08a327f30cd35cbeaa4420a8f63391' into HEAD
2 parents a065590 + ff8c8e3 commit 39f8a4f

20 files changed

+405
-570
lines changed

.eslintignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.gitignore
2+
assets/scripts/*.*
3+
report/**/*.*

app/account/account.routes.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import angular from 'angular'
55

66
angular.module('tc.account').config(routes)
77

8-
routes.$inject = ['$stateProvider']
8+
routes.$inject = ['$stateProvider', 'CONSTANTS']
99

10-
function routes($stateProvider) {
10+
function routes($stateProvider, CONSTANTS) {
1111
var states = {
1212
'auth': {
1313
parent: 'root',
@@ -16,6 +16,27 @@ import angular from 'angular'
1616
authRequired: false
1717
}
1818
},
19+
'login': {
20+
url: '/login?next&code&state&status&userJWTToken&utm_source&utm_medium&utm_campaign',
21+
views: {
22+
'header@': {},
23+
'container@': {},
24+
'footer@': {}
25+
},
26+
data: {
27+
authRequired: false
28+
},
29+
onEnter: ['$state', '$window', '$stateParams', 'logger',
30+
function($state, $window, $stateParams, logger) {
31+
var next = $state.href('dashboard', {}, {absolute: true})
32+
if ($stateParams.next) {
33+
next = decodeURIComponent($stateParams.next)
34+
}
35+
$window.location = CONSTANTS.ACCOUNTS_APP_URL + '?retUrl=' + encodeURIComponent(next)
36+
}
37+
]
38+
39+
},
1940
logout: {
2041
url: '/logout/',
2142
views: {
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: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
var fpFile = event.fpfile
66+
var _file = {
67+
name: scope.filename || fpFile.filename,
68+
container: fpFile.container || scope.fpContainer,
69+
path: fpFile.key,
70+
size: fpFile.size,
71+
mimetype: fpFile.mimetype
72+
}
73+
scope.ngModel = _file
74+
scope.setFileReference({
75+
file: _file,
76+
fieldId: scope.fieldId
77+
})
78+
}
79+
}
80+
}
81+
}
82+
})()
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/index.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,6 @@ require('../assets/css/directives/tc-banner.scss')
121121
require('../assets/css/community/statistics.scss')
122122
require('../assets/css/community/members.scss')
123123
require('../assets/css/community/community.scss')
124-
require('../assets/css/account/reset-password.scss')
125-
require('../assets/css/account/registered-successfully.scss')
126-
require('../assets/css/account/register.scss')
127-
require('../assets/css/account/login.scss')
128-
require('../assets/css/account/account.scss')
129124

130125
function requireContextFiles(files) {
131126
const paths = files.keys()

0 commit comments

Comments
 (0)