This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | /* global Q */ |
||
2 | |||
3 | var React = require("react"); |
||
4 | var ReactDOM = require("react-dom"); |
||
5 | |||
6 | var Events = require('./events.js'); |
||
7 | var Helpers = require('./helpers.js'); |
||
8 | var DeployPlan = require('./DeployPlan.jsx'); |
||
9 | |||
10 | var DeploymentDialog = React.createClass({ |
||
11 | |||
12 | getInitialState: function() { |
||
13 | return { |
||
14 | loading: false, |
||
15 | loadingText: "", |
||
16 | errorText: "", |
||
17 | fetched: true, |
||
18 | last_fetched: "" |
||
19 | }; |
||
20 | }, |
||
21 | componentDidMount: function() { |
||
22 | this.subscriptions.push(Events.subscribe('loading', function(text) { |
||
23 | this.setState({ |
||
24 | loading: true, |
||
25 | success: false, |
||
26 | loadingText: text |
||
27 | }); |
||
28 | }.bind(this))); |
||
29 | this.subscriptions.push(Events.subscribe('loading/done', function() { |
||
30 | this.setState({ |
||
31 | loading: false, |
||
32 | loadingText: '', |
||
33 | success: true |
||
34 | }); |
||
35 | }.bind(this))); |
||
36 | this.subscriptions.push(Events.subscribe('error', function(text) { |
||
37 | this.setState({ |
||
38 | errorText: text, |
||
39 | loading: false, |
||
40 | loadingText: '', |
||
41 | success: false |
||
42 | }); |
||
43 | }.bind(this))); |
||
44 | }, |
||
45 | componentWillUnmount: function() { |
||
46 | // remove subscribers |
||
47 | for (var idx = 0; idx < this.subscriptions.length; idx++) { |
||
0 ignored issues
–
show
Coding Style
introduced
by
![]() |
|||
48 | this.subscriptions[idx].remove(); |
||
49 | } |
||
50 | }, |
||
51 | |||
52 | // subscribers to Events so we can unsubscribe on componentWillUnmount |
||
53 | subscriptions: [], |
||
54 | |||
55 | handleClick: function(e) { |
||
56 | e.preventDefault(); |
||
57 | Events.publish('loading', "Fetching latest code…"); |
||
58 | this.setState({ |
||
59 | fetched: false |
||
60 | }); |
||
61 | |||
62 | Q($.ajax({ |
||
63 | type: "POST", |
||
64 | dataType: 'json', |
||
65 | url: this.props.context.projectUrl + '/fetch' |
||
66 | })) |
||
67 | .then(this.waitForFetchToComplete, this.fetchStatusError) |
||
68 | .then(function() { |
||
69 | Events.publish('loading/done'); |
||
70 | this.setState({ |
||
71 | fetched: true |
||
72 | }); |
||
73 | }.bind(this)) |
||
74 | .catch(this.fetchStatusError) |
||
75 | .done(); |
||
76 | }, |
||
77 | getFetchStatus: function (fetchData) { |
||
0 ignored issues
–
show
|
|||
78 | return Q($.ajax({ |
||
79 | type: "GET", |
||
80 | url: fetchData.href, |
||
81 | dataType: 'json' |
||
82 | })); |
||
83 | }, |
||
84 | waitForFetchToComplete:function (fetchData) { |
||
85 | return this.getFetchStatus(fetchData).then(function (data) { |
||
86 | if (data.status === "Complete") { |
||
87 | return data; |
||
88 | } |
||
89 | if (data.status === "Failed") { |
||
90 | return $.Deferred(function (d) { |
||
91 | return d.reject(data); |
||
92 | }).promise(); |
||
93 | } |
||
94 | return this.waitForFetchToComplete(fetchData); |
||
95 | }.bind(this)); |
||
96 | }, |
||
97 | |||
98 | fetchStatusError: function(data) { |
||
99 | var message = 'Unknown error'; |
||
100 | if (typeof data.responseText !== 'undefined') { |
||
101 | message = data.responseText; |
||
102 | } else if (typeof data.message !== 'undefined') { |
||
103 | message = data.message; |
||
104 | } |
||
105 | Events.publish('error', message); |
||
106 | }, |
||
107 | lastFetchedHandler: function(time_ago) { |
||
108 | this.setState({last_fetched: time_ago}); |
||
109 | }, |
||
110 | render: function() { |
||
111 | var classes = Helpers.classNames({ |
||
112 | "deploy-dropdown": true, |
||
113 | loading: this.state.loading, |
||
114 | success: this.state.success |
||
115 | }); |
||
116 | |||
117 | var form; |
||
118 | |||
119 | if (this.state.errorText !== "") { |
||
120 | form = <ErrorMessages message={this.state.errorText} />; |
||
121 | } else if (this.state.fetched) { |
||
122 | form = ( |
||
123 | <DeployForm |
||
124 | context={this.props.context} |
||
125 | data={this.props.data} |
||
126 | lastFetchedHandler={this.lastFetchedHandler} |
||
127 | /> |
||
128 | ); |
||
129 | } else if (this.state.loading) { |
||
130 | form = <LoadingDeployForm message="Fetching latest code…" />; |
||
131 | } |
||
132 | |||
133 | return ( |
||
134 | <div> |
||
135 | <div className={classes} onClick={this.handleClick}> |
||
0 ignored issues
–
show
|
|||
136 | <span className="status-icon" aria-hidden="true"></span> |
||
137 | <span className="time">last updated {this.state.last_fetched}</span> |
||
138 | <EnvironmentName environmentName={this.props.context.envName} /> |
||
139 | </div> |
||
140 | {form} |
||
141 | </div> |
||
142 | ); |
||
143 | } |
||
144 | }); |
||
145 | |||
146 | function LoadingDeployForm(props) { |
||
147 | return ( |
||
148 | <div className="deploy-form-loading"> |
||
149 | <div className="icon-holder"> |
||
150 | <i className="fa fa-cog fa-spin"></i> |
||
151 | <span>{props.message}</span> |
||
152 | </div> |
||
153 | </div> |
||
154 | ); |
||
155 | } |
||
156 | |||
157 | function ErrorMessages(props) { |
||
158 | return ( |
||
159 | <div className="deploy-dropdown-errors"> |
||
160 | {props.message} |
||
161 | </div> |
||
162 | ); |
||
163 | } |
||
164 | |||
165 | function EnvironmentName(props) { |
||
166 | return ( |
||
167 | <span className="environment-name"> |
||
168 | <i className="fa fa-rocket"> </i> |
||
169 | Deployment options <span className="hidden-xs">for {props.environmentName}</span> |
||
170 | </span> |
||
171 | ); |
||
172 | } |
||
173 | |||
174 | var DeployForm = React.createClass({ |
||
175 | getInitialState: function() { |
||
176 | return { |
||
177 | selectedTab: 1, |
||
178 | data: [], |
||
179 | preselectSha: null |
||
180 | }; |
||
181 | }, |
||
182 | componentDidMount: function() { |
||
183 | this.gitData(); |
||
184 | }, |
||
185 | |||
186 | gitData: function() { |
||
187 | this.setState({ |
||
188 | loading: true |
||
189 | }); |
||
190 | Q($.ajax({ |
||
191 | type: "POST", |
||
192 | dataType: 'json', |
||
193 | url: this.props.context.gitRevisionsUrl |
||
194 | })).then(function(data) { |
||
195 | this.setState({ |
||
196 | loading: false, |
||
197 | data: data.Tabs, |
||
198 | selectedTab: data.preselect_tab ? parseInt(data.preselect_tab, 10) : 1, |
||
199 | preselectSha: data.preselect_sha |
||
200 | }); |
||
201 | this.props.lastFetchedHandler(data.last_fetched); |
||
202 | }.bind(this), function(data) { |
||
203 | Events.publish('error', data); |
||
204 | }); |
||
205 | }, |
||
206 | |||
207 | selectHandler: function(id) { |
||
208 | this.setState({selectedTab: id}); |
||
209 | }, |
||
210 | render: function () { |
||
211 | if (this.state.loading) { |
||
212 | return ( |
||
213 | <LoadingDeployForm message="Loading…" /> |
||
214 | ); |
||
215 | } |
||
216 | |||
217 | return ( |
||
218 | <div className="deploy-form-outer clearfix"> |
||
219 | <form className="form-inline deploy-form" action="POST" action="#"> |
||
0 ignored issues
–
show
|
|||
220 | <DeployTabSelector |
||
221 | data={this.state.data} |
||
222 | onSelect={this.selectHandler} |
||
223 | selectedTab={this.state.selectedTab} |
||
224 | /> |
||
225 | <DeployTabs |
||
226 | context={this.props.context} |
||
227 | data={this.state.data} |
||
228 | selectedTab={this.state.selectedTab} |
||
229 | preselectSha={this.state.preselectSha} |
||
230 | SecurityToken={this.state.SecurityToken} |
||
231 | /> |
||
232 | </form> |
||
233 | </div> |
||
234 | ); |
||
235 | } |
||
236 | }); |
||
237 | |||
238 | function DeployTabSelector(props) { |
||
239 | var selectors = props.data.map(function(tab) { |
||
240 | return ( |
||
241 | <DeployTabSelect |
||
242 | key={tab.id} |
||
243 | tab={tab} |
||
244 | onSelect={props.onSelect} |
||
245 | selectedTab={props.selectedTab} |
||
246 | /> |
||
247 | ); |
||
248 | }); |
||
249 | return ( |
||
250 | <ul className="SelectionGroup tabbedselectiongroup nolabel"> |
||
251 | {selectors} |
||
252 | </ul> |
||
253 | ); |
||
254 | } |
||
255 | |||
256 | var DeployTabSelect = React.createClass({ |
||
257 | handleClick: function(e) { |
||
258 | e.preventDefault(); |
||
259 | this.props.onSelect(this.props.tab.id); |
||
260 | }, |
||
261 | render: function () { |
||
262 | var classes = Helpers.classNames({ |
||
263 | active : (this.props.selectedTab === this.props.tab.id) |
||
264 | }); |
||
265 | return ( |
||
266 | <li className={classes}> |
||
267 | <a |
||
268 | onClick={this.handleClick} |
||
269 | href={"#deploy-tab-" + this.props.tab.id} |
||
270 | > |
||
271 | {this.props.tab.name} |
||
272 | </a> |
||
273 | </li> |
||
274 | ); |
||
275 | } |
||
276 | |||
277 | }); |
||
278 | |||
279 | function DeployTabs(props) { |
||
280 | var tabs = props.data.map(function(tab) { |
||
281 | return ( |
||
282 | <DeployTab |
||
283 | context={props.context} |
||
284 | key={tab.id} |
||
285 | tab={tab} |
||
286 | selectedTab={props.selectedTab} |
||
287 | preselectSha={props.selectedTab === tab.id ? props.preselectSha : null} |
||
288 | SecurityToken={props.SecurityToken} |
||
289 | /> |
||
290 | ); |
||
291 | }); |
||
292 | |||
293 | return ( |
||
294 | <div className="tab-content"> |
||
295 | {tabs} |
||
296 | </div> |
||
297 | ); |
||
298 | } |
||
299 | |||
300 | var DeployTab = React.createClass({ |
||
301 | getInitialState: function() { |
||
302 | var defaultSelectedOptions = []; |
||
303 | for (var i in this.props.tab.options) { |
||
0 ignored issues
–
show
|
|||
304 | var option = this.props.tab.options[i]; |
||
305 | defaultSelectedOptions[option.name] = option.defaultValue; |
||
306 | } |
||
307 | |||
308 | return { |
||
309 | summary: this.getInitialSummaryState(), |
||
310 | selectedOptions: defaultSelectedOptions, |
||
311 | sha: this.props.preselectSha ? this.props.preselectSha : '' |
||
312 | }; |
||
313 | }, |
||
314 | getInitialSummaryState: function() { |
||
315 | return { |
||
316 | changes: {}, |
||
317 | messages: [], |
||
318 | validationCode: '', |
||
319 | estimatedTime: null, |
||
320 | actionCode: null, |
||
321 | initialState: true, |
||
322 | backupChecked: true |
||
323 | }; |
||
324 | }, |
||
325 | componentDidMount: function() { |
||
326 | if (this.shaChosen()) { |
||
327 | this.changeSha(this.state.sha); |
||
328 | } |
||
329 | }, |
||
330 | OptionChangeHandler: function(event) { |
||
331 | var selectedOptions = this.state.selectedOptions; |
||
332 | selectedOptions[event.target.name] = event.target.checked; |
||
333 | this.setState({ |
||
334 | selectedOptions: selectedOptions |
||
335 | }); |
||
336 | }, |
||
337 | SHAChangeHandler: function(event) { |
||
338 | this.setState({ |
||
339 | sha: event.target.value |
||
340 | }); |
||
341 | }, |
||
342 | changeSha: function(sha) { |
||
343 | this.setState({ |
||
344 | summary: this.getInitialSummaryState() |
||
345 | }); |
||
346 | |||
347 | Events.publish('change_loading'); |
||
348 | |||
349 | var branch = null; |
||
350 | |||
351 | for (var i in this.props.tab.field_data) { |
||
352 | if (this.props.tab.field_data[i].id === sha) { |
||
353 | branch = this.props.tab.field_data[i].branch_name; |
||
354 | } |
||
355 | } |
||
356 | |||
357 | var summaryData = { |
||
358 | sha: sha, |
||
359 | branch: branch, |
||
360 | DispatcherSecurityID: this.props.SecurityToken |
||
361 | }; |
||
362 | // merge the 'advanced' options if they are set |
||
363 | for (var attrname in this.state.selectedOptions) { |
||
364 | if (this.state.selectedOptions.hasOwnProperty(attrname)) { |
||
365 | summaryData[attrname] = this.state.selectedOptions[attrname]; |
||
366 | } |
||
367 | } |
||
368 | |||
369 | Q($.ajax({ |
||
370 | type: "POST", |
||
371 | dataType: 'json', |
||
372 | url: this.props.context.envUrl + '/deploy_summary', |
||
373 | data: summaryData |
||
374 | })).then(function(data) { |
||
375 | this.setState({ |
||
376 | summary: data |
||
377 | }); |
||
378 | Events.publish('change_loading/done'); |
||
379 | }.bind(this), function() { |
||
380 | Events.publish('change_loading/done'); |
||
381 | }); |
||
382 | }, |
||
383 | |||
384 | changeHandler: function(event) { |
||
385 | event.preventDefault(); |
||
386 | if (event.target.value === "") { |
||
387 | return; |
||
388 | } |
||
389 | var sha = ReactDOM.findDOMNode(this.refs.sha_selector.refs.sha).value; |
||
0 ignored issues
–
show
|
|||
390 | return this.changeSha(sha); |
||
0 ignored issues
–
show
|
|||
391 | }, |
||
392 | |||
393 | shaChosen: function() { |
||
394 | return (this.state.sha !== ''); |
||
395 | }, |
||
396 | |||
397 | render: function () { |
||
398 | var classes = Helpers.classNames({ |
||
399 | "tab-pane": true, |
||
400 | clearfix: true, |
||
401 | active: (this.props.selectedTab === this.props.tab.id) |
||
402 | }); |
||
403 | |||
404 | // setup the dropdown or the text input for selecting a SHA |
||
405 | var selector; |
||
406 | if (this.props.tab.field_type === 'dropdown') { |
||
407 | selector = ( |
||
408 | <SelectorDropdown |
||
409 | ref="sha_selector" |
||
0 ignored issues
–
show
|
|||
410 | tab={this.props.tab} |
||
411 | changeHandler={this.SHAChangeHandler} |
||
412 | defaultValue={this.state.sha} |
||
413 | /> |
||
414 | ); |
||
415 | } else if (this.props.tab.field_type === 'textfield') { |
||
416 | selector = ( |
||
417 | <SelectorText |
||
418 | ref="sha_selector" |
||
0 ignored issues
–
show
|
|||
419 | tab={this.props.tab} |
||
420 | changeHandler={this.SHAChangeHandler} |
||
421 | defaultValue={this.state.sha} |
||
422 | /> |
||
423 | ); |
||
424 | } |
||
425 | |||
426 | return ( |
||
427 | <div id={"deploy-tab-" + this.props.tab.id} className={classes}> |
||
428 | <div className="section"> |
||
429 | <div htmlFor={this.props.tab.field_id} className="header"> |
||
430 | <span className="numberCircle">1</span> {this.props.tab.field_label} |
||
431 | </div> |
||
432 | {selector} |
||
433 | <DeployOptions |
||
434 | tab={this.props.tab} |
||
435 | changeHandler={this.OptionChangeHandler} |
||
436 | options={this.props.tab.options} |
||
437 | selectedOptions={this.state.selectedOptions} |
||
438 | /> |
||
439 | <VerifyButton disabled={!this.shaChosen()} changeHandler={this.changeHandler} /> |
||
440 | </div> |
||
441 | <DeployPlan context={this.props.context} summary={this.state.summary} /> |
||
442 | </div> |
||
443 | ); |
||
444 | } |
||
445 | }); |
||
446 | |||
447 | var SelectorDropdown = React.createClass({ |
||
448 | componentDidMount: function() { |
||
449 | $(ReactDOM.findDOMNode(this.refs.sha)).select2({ |
||
0 ignored issues
–
show
|
|||
450 | // Load data into the select2. |
||
451 | // The format supports optgroups, and looks like this: |
||
452 | // [{text: 'optgroup text', children: [{id: '<sha>', text: '<inner text>'}]}] |
||
453 | data: this.props.tab.field_data |
||
454 | }).val(this.props.defaultValue); |
||
455 | |||
456 | if (this.props.changeHandler) { |
||
457 | $(ReactDOM.findDOMNode(this.refs.sha)).select2().on("change", this.props.changeHandler); |
||
0 ignored issues
–
show
|
|||
458 | } |
||
459 | }, |
||
460 | |||
461 | render: function() { |
||
462 | // From https://select2.github.io/examples.html "The best way to ensure that Select2 is using a percent based |
||
463 | // width is to inline the style declaration into the tag". |
||
464 | var style = {width: '100%'}; |
||
465 | |||
466 | return ( |
||
467 | <div> |
||
468 | <div className="field"> |
||
469 | <select |
||
470 | ref="sha" |
||
0 ignored issues
–
show
|
|||
471 | id={this.props.tab.field_id} |
||
472 | name="sha" |
||
473 | className="dropdown" |
||
474 | onChange={this.props.changeHandler} |
||
475 | style={style} |
||
476 | > |
||
477 | <option value="">Select {this.props.tab.field_id}</option> |
||
478 | </select> |
||
479 | </div> |
||
480 | </div> |
||
481 | ); |
||
482 | } |
||
483 | }); |
||
484 | |||
485 | var SelectorText = React.createClass({ |
||
486 | render: function() { |
||
487 | return ( |
||
488 | <div className="field"> |
||
489 | <input |
||
490 | type="text" |
||
491 | ref="sha" |
||
0 ignored issues
–
show
|
|||
492 | id={this.props.tab.field_id} |
||
493 | name="sha" |
||
494 | className="text" |
||
495 | defaultValue={this.props.defaultValue} |
||
496 | onChange={this.props.changeHandler} |
||
497 | /> |
||
498 | </div> |
||
499 | ); |
||
500 | } |
||
501 | }); |
||
502 | |||
503 | function VerifyButton(props) { |
||
504 | return ( |
||
505 | <div> |
||
506 | <button |
||
507 | disabled={props.disabled} |
||
508 | value="Verify deployment" |
||
509 | className="btn btn-default" |
||
510 | onClick={props.changeHandler} |
||
511 | > |
||
512 | Verify deployment |
||
513 | </button> |
||
514 | </div> |
||
515 | ); |
||
516 | } |
||
517 | |||
518 | function DeployOptions(props) { |
||
519 | var options = []; |
||
520 | for (var i in props.options) { |
||
0 ignored issues
–
show
|
|||
521 | var name = props.options[i].name; |
||
522 | var title = props.options[i].title; |
||
523 | var checked = false; |
||
524 | |||
525 | for (var optionName in props.selectedOptions) { |
||
526 | if (optionName === name) { |
||
527 | checked = props.selectedOptions[optionName]; |
||
528 | } |
||
529 | } |
||
530 | |||
531 | options.push( |
||
532 | <DeployOption |
||
533 | key={i} |
||
534 | changeHandler={props.changeHandler} |
||
535 | name={name} |
||
536 | title={title} |
||
537 | checked={checked} |
||
538 | /> |
||
539 | ); |
||
540 | } |
||
541 | |||
542 | return ( |
||
543 | <div className="deploy-options"> |
||
544 | {options} |
||
545 | </div> |
||
546 | ); |
||
547 | } |
||
548 | |||
549 | function DeployOption(props) { |
||
550 | return ( |
||
551 | <div className="fieldcheckbox"> |
||
552 | <label htmlFor={props.name}> |
||
553 | <input |
||
554 | type="checkbox" |
||
555 | name={props.name} |
||
556 | id={props.name} |
||
557 | checked={props.checked} |
||
558 | onChange={props.changeHandler} |
||
559 | /> |
||
560 | {props.title} |
||
561 | </label> |
||
562 | </div> |
||
563 | ); |
||
564 | } |
||
565 | |||
566 | module.exports = DeploymentDialog; |
||
567 |