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 | <?php |
||
2 | |||
3 | /** |
||
4 | * God controller for the deploynaut interface |
||
5 | * |
||
6 | * @package deploynaut |
||
7 | * @subpackage control |
||
8 | */ |
||
9 | class DNRoot extends Controller implements PermissionProvider, TemplateGlobalProvider { |
||
0 ignored issues
–
show
The property $allowed_actions is not named in camelCase.
This check marks property names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes ![]() The property $url_handlers is not named in camelCase.
This check marks property names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes ![]() The property $support_links is not named in camelCase.
This check marks property names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes ![]() The property $platform_specific_strings is not named in camelCase.
This check marks property names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes ![]() The property $action_types is not named in camelCase.
This check marks property names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes ![]() The property $logged_in_links is not named in camelCase.
This check marks property names that have not been written in camelCase. In camelCase names are written without any punctuation, the start of each new word being marked
by a capital letter. Thus the name database connection string becomes ![]() |
|||
10 | |||
11 | /** |
||
12 | * @const string - action type for actions that perform deployments |
||
13 | */ |
||
14 | const ACTION_DEPLOY = 'deploy'; |
||
15 | |||
16 | /** |
||
17 | * @const string - action type for actions that manipulate snapshots |
||
18 | */ |
||
19 | const ACTION_SNAPSHOT = 'snapshot'; |
||
20 | |||
21 | const ACTION_ENVIRONMENTS = 'createenv'; |
||
22 | |||
23 | const PROJECT_OVERVIEW = 'overview'; |
||
24 | |||
25 | /** |
||
26 | * Allow advanced options on deployments |
||
27 | */ |
||
28 | const DEPLOYNAUT_ADVANCED_DEPLOY_OPTIONS = 'DEPLOYNAUT_ADVANCED_DEPLOY_OPTIONS'; |
||
29 | |||
30 | const ALLOW_PROD_DEPLOYMENT = 'ALLOW_PROD_DEPLOYMENT'; |
||
31 | |||
32 | const ALLOW_NON_PROD_DEPLOYMENT = 'ALLOW_NON_PROD_DEPLOYMENT'; |
||
33 | |||
34 | const ALLOW_PROD_SNAPSHOT = 'ALLOW_PROD_SNAPSHOT'; |
||
35 | |||
36 | const ALLOW_NON_PROD_SNAPSHOT = 'ALLOW_NON_PROD_SNAPSHOT'; |
||
37 | |||
38 | const ALLOW_CREATE_ENVIRONMENT = 'ALLOW_CREATE_ENVIRONMENT'; |
||
39 | |||
40 | /** |
||
41 | * @var array |
||
42 | */ |
||
43 | protected static $_project_cache = []; |
||
44 | |||
45 | /** |
||
46 | * @var DNData |
||
47 | */ |
||
48 | protected $data; |
||
49 | |||
50 | /** |
||
51 | * @var string |
||
52 | */ |
||
53 | private $actionType = self::ACTION_DEPLOY; |
||
54 | |||
55 | /** |
||
56 | * @var array |
||
57 | */ |
||
58 | private static $allowed_actions = [ |
||
0 ignored issues
–
show
|
|||
59 | 'projects', |
||
60 | 'nav', |
||
61 | 'update', |
||
62 | 'project', |
||
63 | 'toggleprojectstar', |
||
64 | 'branch', |
||
65 | 'environment', |
||
66 | 'createenvlog', |
||
67 | 'createenv', |
||
68 | 'getDeployForm', |
||
69 | 'doDeploy', |
||
70 | 'deploy', |
||
71 | 'deploylog', |
||
72 | 'abortDeploy', |
||
73 | 'getDataTransferForm', |
||
74 | 'transfer', |
||
75 | 'transferlog', |
||
76 | 'snapshots', |
||
77 | 'createsnapshot', |
||
78 | 'snapshotslog', |
||
79 | 'uploadsnapshot', |
||
80 | 'getCreateEnvironmentForm', |
||
81 | 'getUploadSnapshotForm', |
||
82 | 'getPostSnapshotForm', |
||
83 | 'getDataTransferRestoreForm', |
||
84 | 'getDeleteForm', |
||
85 | 'getMoveForm', |
||
86 | 'restoresnapshot', |
||
87 | 'deletesnapshot', |
||
88 | 'movesnapshot', |
||
89 | 'postsnapshotsuccess', |
||
90 | 'gitRevisions', |
||
91 | 'deploySummary', |
||
92 | 'startDeploy' |
||
93 | ]; |
||
94 | |||
95 | /** |
||
96 | * URL handlers pretending that we have a deep URL structure. |
||
97 | */ |
||
98 | private static $url_handlers = [ |
||
0 ignored issues
–
show
|
|||
99 | 'project/$Project/environment/$Environment/DeployForm' => 'getDeployForm', |
||
100 | 'project/$Project/createsnapshot/DataTransferForm' => 'getDataTransferForm', |
||
101 | 'project/$Project/DataTransferForm' => 'getDataTransferForm', |
||
102 | 'project/$Project/DataTransferRestoreForm' => 'getDataTransferRestoreForm', |
||
103 | 'project/$Project/DeleteForm' => 'getDeleteForm', |
||
104 | 'project/$Project/MoveForm' => 'getMoveForm', |
||
105 | 'project/$Project/UploadSnapshotForm' => 'getUploadSnapshotForm', |
||
106 | 'project/$Project/PostSnapshotForm' => 'getPostSnapshotForm', |
||
107 | 'project/$Project/environment/$Environment/deploy_summary' => 'deploySummary', |
||
108 | 'project/$Project/environment/$Environment/git_revisions' => 'gitRevisions', |
||
109 | 'project/$Project/environment/$Environment/start-deploy' => 'startDeploy', |
||
110 | 'project/$Project/environment/$Environment/deploy/$Identifier/log' => 'deploylog', |
||
111 | 'project/$Project/environment/$Environment/deploy/$Identifier/abort-deploy' => 'abortDeploy', |
||
112 | 'project/$Project/environment/$Environment/deploy/$Identifier' => 'deploy', |
||
113 | 'project/$Project/transfer/$Identifier/log' => 'transferlog', |
||
114 | 'project/$Project/transfer/$Identifier' => 'transfer', |
||
115 | 'project/$Project/environment/$Environment' => 'environment', |
||
116 | 'project/$Project/createenv/$Identifier/log' => 'createenvlog', |
||
117 | 'project/$Project/createenv/$Identifier' => 'createenv', |
||
118 | 'project/$Project/CreateEnvironmentForm' => 'getCreateEnvironmentForm', |
||
119 | 'project/$Project/branch' => 'branch', |
||
120 | 'project/$Project/build/$Build' => 'build', |
||
121 | 'project/$Project/restoresnapshot/$DataArchiveID' => 'restoresnapshot', |
||
122 | 'project/$Project/deletesnapshot/$DataArchiveID' => 'deletesnapshot', |
||
123 | 'project/$Project/movesnapshot/$DataArchiveID' => 'movesnapshot', |
||
124 | 'project/$Project/update' => 'update', |
||
125 | 'project/$Project/snapshots' => 'snapshots', |
||
126 | 'project/$Project/createsnapshot' => 'createsnapshot', |
||
127 | 'project/$Project/uploadsnapshot' => 'uploadsnapshot', |
||
128 | 'project/$Project/snapshotslog' => 'snapshotslog', |
||
129 | 'project/$Project/postsnapshotsuccess/$DataArchiveID' => 'postsnapshotsuccess', |
||
130 | 'project/$Project/star' => 'toggleprojectstar', |
||
131 | 'project/$Project' => 'project', |
||
132 | 'nav/$Project' => 'nav', |
||
133 | 'projects' => 'projects', |
||
134 | ]; |
||
135 | |||
136 | /** |
||
137 | * @var array |
||
138 | */ |
||
139 | private static $support_links = []; |
||
0 ignored issues
–
show
|
|||
140 | |||
141 | /** |
||
142 | * @var array |
||
143 | */ |
||
144 | private static $logged_in_links = []; |
||
0 ignored issues
–
show
|
|||
145 | |||
146 | /** |
||
147 | * @var array |
||
148 | */ |
||
149 | private static $platform_specific_strings = []; |
||
0 ignored issues
–
show
|
|||
150 | |||
151 | /** |
||
152 | * @var array |
||
153 | */ |
||
154 | private static $action_types = [ |
||
0 ignored issues
–
show
|
|||
155 | self::ACTION_DEPLOY, |
||
156 | self::ACTION_SNAPSHOT, |
||
157 | self::PROJECT_OVERVIEW |
||
158 | ]; |
||
159 | |||
160 | /** |
||
161 | * Include requirements that deploynaut needs, such as javascript. |
||
162 | */ |
||
163 | public static function include_requirements() { |
||
164 | |||
165 | // JS should always go to the bottom, otherwise there's the risk that Requirements |
||
166 | // puts them halfway through the page to the nearest <script> tag. We don't want that. |
||
167 | Requirements::set_force_js_to_bottom(true); |
||
168 | |||
169 | // todo these should be bundled into the same JS as the others in "static" below. |
||
170 | // We've deliberately not used combined_files as it can mess with some of the JS used |
||
171 | // here and cause sporadic errors. |
||
172 | Requirements::javascript('deploynaut/javascript/jquery.js'); |
||
173 | Requirements::javascript('deploynaut/javascript/bootstrap.js'); |
||
174 | Requirements::javascript('deploynaut/javascript/q.js'); |
||
175 | Requirements::javascript('deploynaut/javascript/tablefilter.js'); |
||
176 | Requirements::javascript('deploynaut/javascript/deploynaut.js'); |
||
177 | |||
178 | Requirements::javascript('deploynaut/javascript/bootstrap.file-input.js'); |
||
179 | Requirements::javascript('deploynaut/thirdparty/select2/dist/js/select2.min.js'); |
||
180 | Requirements::javascript('deploynaut/javascript/selectize.js'); |
||
181 | Requirements::javascript('deploynaut/thirdparty/bootstrap-switch/dist/js/bootstrap-switch.min.js'); |
||
182 | Requirements::javascript('deploynaut/javascript/material.js'); |
||
183 | |||
184 | // Load the buildable dependencies only if not loaded centrally. |
||
185 | if (!is_dir(BASE_PATH . DIRECTORY_SEPARATOR . 'static')) { |
||
186 | if (\Director::isDev()) { |
||
187 | \Requirements::javascript('deploynaut/static/bundle-debug.js'); |
||
188 | } else { |
||
189 | \Requirements::javascript('deploynaut/static/bundle.js'); |
||
190 | } |
||
191 | } |
||
192 | |||
193 | // We need to include javascript here so that prerequisite js object(s) from |
||
194 | // the deploynaut module have been loaded |
||
195 | Requirements::javascript('static/platform.js'); |
||
196 | |||
197 | Requirements::css('deploynaut/static/style.css'); |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * @return ArrayList |
||
202 | */ |
||
203 | public static function get_support_links() { |
||
204 | $supportLinks = self::config()->support_links; |
||
205 | if ($supportLinks) { |
||
206 | return new ArrayList($supportLinks); |
||
207 | } |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * @return ArrayList |
||
212 | */ |
||
213 | public static function get_logged_in_links() { |
||
214 | $loggedInLinks = self::config()->logged_in_links; |
||
215 | if ($loggedInLinks) { |
||
216 | return new ArrayList($loggedInLinks); |
||
217 | } |
||
218 | } |
||
219 | |||
220 | /** |
||
221 | * Return the platform title if configured, defaulting to "Deploynaut". |
||
222 | * @return string |
||
223 | */ |
||
224 | public static function platform_title() { |
||
225 | if (defined('DEPLOYNAUT_PLATFORM_TITLE')) { |
||
226 | return DEPLOYNAUT_PLATFORM_TITLE; |
||
227 | } |
||
228 | return 'Deploynaut'; |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * @return array |
||
233 | */ |
||
234 | public static function get_template_global_variables() { |
||
235 | return [ |
||
236 | 'PlatformTitle' => 'platform_title', |
||
237 | 'RedisUnavailable' => 'RedisUnavailable', |
||
238 | 'RedisWorkersCount' => 'RedisWorkersCount', |
||
239 | 'SidebarLinks' => 'SidebarLinks', |
||
240 | 'SupportLinks' => 'get_support_links', |
||
241 | 'LoggedInLinks' => 'get_logged_in_links', |
||
242 | ]; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | */ |
||
247 | public function init() { |
||
248 | parent::init(); |
||
249 | |||
250 | if (!Member::currentUser() && !Session::get('AutoLoginHash')) { |
||
251 | return Security::permissionFailure(); |
||
252 | } |
||
253 | |||
254 | // Block framework jquery |
||
255 | Requirements::block(FRAMEWORK_DIR . '/thirdparty/jquery/jquery.js'); |
||
256 | |||
257 | self::include_requirements(); |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * @return string |
||
262 | */ |
||
263 | public function Link() { |
||
264 | return "naut/"; |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Actions |
||
269 | * |
||
270 | * @param \SS_HTTPRequest $request |
||
271 | * @return \SS_HTTPResponse |
||
272 | */ |
||
273 | public function index(\SS_HTTPRequest $request) { |
||
274 | return $this->redirect($this->Link() . 'projects/'); |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Action |
||
279 | * |
||
280 | * @param \SS_HTTPRequest $request |
||
281 | * @return string - HTML |
||
282 | */ |
||
283 | public function projects(\SS_HTTPRequest $request) { |
||
284 | // Performs canView permission check by limiting visible projects in DNProjectsList() call. |
||
285 | return $this->customise([ |
||
286 | 'Title' => 'Projects', |
||
287 | ])->render(); |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * @param \SS_HTTPRequest $request |
||
292 | * @return HTMLText |
||
293 | */ |
||
294 | public function nav(\SS_HTTPRequest $request) { |
||
295 | return $this->renderWith('Nav'); |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * Return a link to the navigation template used for AJAX requests. |
||
300 | * @return string |
||
301 | */ |
||
302 | public function NavLink() { |
||
303 | $currentProject = $this->getCurrentProject(); |
||
304 | $projectName = $currentProject ? $currentProject->Name : null; |
||
305 | return Controller::join_links(Director::absoluteBaseURL(), 'naut', 'nav', $projectName); |
||
306 | } |
||
307 | |||
308 | /** |
||
309 | * Action |
||
310 | * |
||
311 | * @param \SS_HTTPRequest $request |
||
312 | * @return SS_HTTPResponse - HTML |
||
313 | */ |
||
314 | public function snapshots(\SS_HTTPRequest $request) { |
||
315 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
316 | return $this->getCustomisedViewSection('SnapshotsSection', 'Data Snapshots'); |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Action |
||
321 | * |
||
322 | * @param \SS_HTTPRequest $request |
||
323 | * @return string - HTML |
||
324 | */ |
||
325 | View Code Duplication | public function createsnapshot(\SS_HTTPRequest $request) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
326 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
327 | |||
328 | // Performs canView permission check by limiting visible projects |
||
329 | $project = $this->getCurrentProject(); |
||
330 | if (!$project) { |
||
331 | return $this->project404Response(); |
||
332 | } |
||
333 | |||
334 | if (!$project->canBackup()) { |
||
335 | return new SS_HTTPResponse("Not allowed to create snapshots on any environments", 401); |
||
336 | } |
||
337 | |||
338 | return $this->customise([ |
||
339 | 'Title' => 'Create Data Snapshot', |
||
340 | 'SnapshotsSection' => 1, |
||
341 | 'DataTransferForm' => $this->getDataTransferForm($request) |
||
342 | ])->render(); |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Action |
||
347 | * |
||
348 | * @param \SS_HTTPRequest $request |
||
349 | * @return string - HTML |
||
350 | */ |
||
351 | View Code Duplication | public function uploadsnapshot(\SS_HTTPRequest $request) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
352 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
353 | |||
354 | // Performs canView permission check by limiting visible projects |
||
355 | $project = $this->getCurrentProject(); |
||
356 | if (!$project) { |
||
357 | return $this->project404Response(); |
||
358 | } |
||
359 | |||
360 | if (!$project->canUploadArchive()) { |
||
361 | return new SS_HTTPResponse("Not allowed to upload", 401); |
||
362 | } |
||
363 | |||
364 | return $this->customise([ |
||
365 | 'SnapshotsSection' => 1, |
||
366 | 'UploadSnapshotForm' => $this->getUploadSnapshotForm($request), |
||
367 | 'PostSnapshotForm' => $this->getPostSnapshotForm($request) |
||
368 | ])->render(); |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * Return the upload limit for snapshot uploads |
||
373 | * @return string |
||
374 | */ |
||
375 | public function UploadLimit() { |
||
376 | return File::format_size(min( |
||
377 | File::ini2bytes(ini_get('upload_max_filesize')), |
||
378 | File::ini2bytes(ini_get('post_max_size')) |
||
379 | )); |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * Construct the upload form. |
||
384 | * |
||
385 | * @param \SS_HTTPRequest $request |
||
386 | * @return Form |
||
387 | */ |
||
388 | public function getUploadSnapshotForm(\SS_HTTPRequest $request) { |
||
389 | // Performs canView permission check by limiting visible projects |
||
390 | $project = $this->getCurrentProject(); |
||
391 | if (!$project) { |
||
392 | return $this->project404Response(); |
||
393 | } |
||
394 | |||
395 | if (!$project->canUploadArchive()) { |
||
396 | return new SS_HTTPResponse("Not allowed to upload", 401); |
||
397 | } |
||
398 | |||
399 | // Framing an environment as a "group of people with download access" |
||
400 | // makes more sense to the user here, while still allowing us to enforce |
||
401 | // environment specific restrictions on downloading the file later on. |
||
402 | $envs = $project->DNEnvironmentList()->filterByCallback(function ($item) { |
||
403 | return $item->canUploadArchive(); |
||
404 | }); |
||
405 | $envsMap = []; |
||
406 | foreach ($envs as $env) { |
||
407 | $envsMap[$env->ID] = $env->Name; |
||
408 | } |
||
409 | |||
410 | $maxSize = min(File::ini2bytes(ini_get('upload_max_filesize')), File::ini2bytes(ini_get('post_max_size'))); |
||
411 | $fileField = DataArchiveFileField::create('ArchiveFile', 'File'); |
||
412 | $fileField->getValidator()->setAllowedExtensions(['sspak']); |
||
413 | $fileField->getValidator()->setAllowedMaxFileSize(['*' => $maxSize]); |
||
414 | |||
415 | $form = Form::create( |
||
416 | $this, |
||
417 | 'UploadSnapshotForm', |
||
418 | FieldList::create( |
||
419 | $fileField, |
||
420 | DropdownField::create('Mode', 'What does this file contain?', DNDataArchive::get_mode_map()), |
||
421 | DropdownField::create('EnvironmentID', 'Initial ownership of the file', $envsMap) |
||
422 | ->setEmptyString('Select an environment') |
||
423 | ), |
||
424 | FieldList::create( |
||
425 | FormAction::create('doUploadSnapshot', 'Upload File') |
||
426 | ->addExtraClass('btn') |
||
427 | ), |
||
428 | RequiredFields::create('ArchiveFile') |
||
429 | ); |
||
430 | |||
431 | $form->disableSecurityToken(); |
||
432 | $form->addExtraClass('fields-wide'); |
||
433 | // Tweak the action so it plays well with our fake URL structure. |
||
434 | $form->setFormAction($project->Link() . '/UploadSnapshotForm'); |
||
435 | |||
436 | return $form; |
||
437 | } |
||
438 | |||
439 | /** |
||
440 | * @param array $data |
||
441 | * @param Form $form |
||
442 | * |
||
443 | * @return bool|HTMLText|SS_HTTPResponse |
||
444 | */ |
||
445 | public function doUploadSnapshot($data, \Form $form) { |
||
446 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
447 | |||
448 | // Performs canView permission check by limiting visible projects |
||
449 | $project = $this->getCurrentProject(); |
||
450 | if (!$project) { |
||
451 | return $this->project404Response(); |
||
452 | } |
||
453 | |||
454 | $validEnvs = $project->DNEnvironmentList() |
||
455 | ->filterByCallback(function ($item) { |
||
456 | return $item->canUploadArchive(); |
||
457 | }); |
||
458 | |||
459 | // Validate $data['EnvironmentID'] by checking against $validEnvs. |
||
460 | $environment = $validEnvs->find('ID', $data['EnvironmentID']); |
||
461 | if (!$environment) { |
||
462 | throw new LogicException('Invalid environment'); |
||
463 | } |
||
464 | |||
465 | $this->validateSnapshotMode($data['Mode']); |
||
466 | |||
467 | $dataArchive = DNDataArchive::create([ |
||
468 | 'AuthorID' => Member::currentUserID(), |
||
469 | 'EnvironmentID' => $data['EnvironmentID'], |
||
470 | 'IsManualUpload' => true, |
||
471 | ]); |
||
472 | // needs an ID and transfer to determine upload path |
||
473 | $dataArchive->write(); |
||
474 | $dataTransfer = DNDataTransfer::create([ |
||
475 | 'AuthorID' => Member::currentUserID(), |
||
476 | 'Mode' => $data['Mode'], |
||
477 | 'Origin' => 'ManualUpload', |
||
478 | 'EnvironmentID' => $data['EnvironmentID'] |
||
479 | ]); |
||
480 | $dataTransfer->write(); |
||
481 | $dataArchive->DataTransfers()->add($dataTransfer); |
||
482 | $form->saveInto($dataArchive); |
||
483 | $dataArchive->write(); |
||
484 | $workingDir = TEMP_FOLDER . DIRECTORY_SEPARATOR . 'deploynaut-transfer-' . $dataTransfer->ID; |
||
485 | |||
486 | View Code Duplication | $cleanupFn = function () use ($workingDir, $dataTransfer, $dataArchive) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
487 | $process = new AbortableProcess(sprintf('rm -rf %s', escapeshellarg($workingDir))); |
||
488 | $process->setTimeout(120); |
||
489 | $process->run(); |
||
490 | $dataTransfer->delete(); |
||
491 | $dataArchive->delete(); |
||
492 | }; |
||
493 | |||
494 | // extract the sspak contents so we can inspect them |
||
495 | try { |
||
496 | $dataArchive->extractArchive($workingDir); |
||
497 | } catch (Exception $e) { |
||
498 | $cleanupFn(); |
||
499 | $form->sessionMessage( |
||
500 | 'There was a problem trying to open your snapshot for processing. Please try uploading again', |
||
501 | 'bad' |
||
502 | ); |
||
503 | return $this->redirectBack(); |
||
504 | } |
||
505 | |||
506 | // validate that the sspak contents match the declared contents |
||
507 | $result = $dataArchive->validateArchiveContents(); |
||
508 | if (!$result->valid()) { |
||
509 | $cleanupFn(); |
||
510 | $form->sessionMessage($result->message(), 'bad'); |
||
511 | return $this->redirectBack(); |
||
512 | } |
||
513 | |||
514 | // fix file permissions of extracted sspak files then re-build the sspak |
||
515 | try { |
||
516 | $dataArchive->fixArchivePermissions($workingDir); |
||
517 | $dataArchive->setArchiveFromFiles($workingDir); |
||
518 | } catch (Exception $e) { |
||
519 | $cleanupFn(); |
||
520 | $form->sessionMessage( |
||
521 | 'There was a problem processing your snapshot. Please try uploading again', |
||
522 | 'bad' |
||
523 | ); |
||
524 | return $this->redirectBack(); |
||
525 | } |
||
526 | |||
527 | // cleanup any extracted sspak contents lying around |
||
528 | $process = new AbortableProcess(sprintf('rm -rf %s', escapeshellarg($workingDir))); |
||
529 | $process->setTimeout(120); |
||
530 | $process->run(); |
||
531 | |||
532 | return $this->customise([ |
||
533 | 'Project' => $project, |
||
534 | 'CurrentProject' => $project, |
||
535 | 'SnapshotsSection' => 1, |
||
536 | 'DataArchive' => $dataArchive, |
||
537 | 'DataTransferRestoreForm' => $this->getDataTransferRestoreForm($this->request, $dataArchive), |
||
538 | 'BackURL' => $project->Link('snapshots') |
||
539 | ])->renderWith(['DNRoot_uploadsnapshot', 'DNRoot']); |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * @param \SS_HTTPRequest $request |
||
544 | * @return Form |
||
545 | */ |
||
546 | public function getPostSnapshotForm(\SS_HTTPRequest $request) { |
||
547 | // Performs canView permission check by limiting visible projects |
||
548 | $project = $this->getCurrentProject(); |
||
549 | if (!$project) { |
||
550 | return $this->project404Response(); |
||
551 | } |
||
552 | |||
553 | if (!$project->canUploadArchive()) { |
||
554 | return new SS_HTTPResponse("Not allowed to upload", 401); |
||
555 | } |
||
556 | |||
557 | // Framing an environment as a "group of people with download access" |
||
558 | // makes more sense to the user here, while still allowing us to enforce |
||
559 | // environment specific restrictions on downloading the file later on. |
||
560 | $envs = $project->DNEnvironmentList()->filterByCallback(function ($item) { |
||
561 | return $item->canUploadArchive(); |
||
562 | }); |
||
563 | $envsMap = []; |
||
564 | foreach ($envs as $env) { |
||
565 | $envsMap[$env->ID] = $env->Name; |
||
566 | } |
||
567 | |||
568 | $form = Form::create( |
||
569 | $this, |
||
570 | 'PostSnapshotForm', |
||
571 | FieldList::create( |
||
572 | DropdownField::create('Mode', 'What does this file contain?', DNDataArchive::get_mode_map()), |
||
573 | DropdownField::create('EnvironmentID', 'Initial ownership of the file', $envsMap) |
||
574 | ->setEmptyString('Select an environment') |
||
575 | ), |
||
576 | FieldList::create( |
||
577 | FormAction::create('doPostSnapshot', 'Submit request') |
||
578 | ->addExtraClass('btn') |
||
579 | ), |
||
580 | RequiredFields::create('File') |
||
581 | ); |
||
582 | |||
583 | $form->disableSecurityToken(); |
||
584 | $form->addExtraClass('fields-wide'); |
||
585 | // Tweak the action so it plays well with our fake URL structure. |
||
586 | $form->setFormAction($project->Link() . '/PostSnapshotForm'); |
||
587 | |||
588 | return $form; |
||
589 | } |
||
590 | |||
591 | /** |
||
592 | * @param array $data |
||
593 | * @param Form $form |
||
594 | * |
||
595 | * @return SS_HTTPResponse |
||
596 | */ |
||
597 | public function doPostSnapshot($data, $form) { |
||
598 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
599 | |||
600 | $project = $this->getCurrentProject(); |
||
601 | if (!$project) { |
||
602 | return $this->project404Response(); |
||
603 | } |
||
604 | |||
605 | $validEnvs = $project->DNEnvironmentList()->filterByCallback(function ($item) { |
||
606 | return $item->canUploadArchive(); |
||
607 | }); |
||
608 | |||
609 | // Validate $data['EnvironmentID'] by checking against $validEnvs. |
||
610 | $environment = $validEnvs->find('ID', $data['EnvironmentID']); |
||
611 | if (!$environment) { |
||
612 | throw new LogicException('Invalid environment'); |
||
613 | } |
||
614 | |||
615 | $dataArchive = DNDataArchive::create([ |
||
616 | 'UploadToken' => DNDataArchive::generate_upload_token(), |
||
617 | ]); |
||
618 | $form->saveInto($dataArchive); |
||
619 | $dataArchive->write(); |
||
620 | |||
621 | return $this->redirect(Controller::join_links( |
||
622 | $project->Link(), |
||
623 | 'postsnapshotsuccess', |
||
624 | $dataArchive->ID |
||
625 | )); |
||
626 | } |
||
627 | |||
628 | /** |
||
629 | * Action |
||
630 | * |
||
631 | * @param \SS_HTTPRequest $request |
||
632 | * @return SS_HTTPResponse - HTML |
||
633 | */ |
||
634 | public function snapshotslog(\SS_HTTPRequest $request) { |
||
635 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
636 | return $this->getCustomisedViewSection('SnapshotsSection', 'Snapshots log'); |
||
637 | } |
||
638 | |||
639 | /** |
||
640 | * @param \SS_HTTPRequest $request |
||
641 | * @return SS_HTTPResponse|string |
||
642 | * @throws SS_HTTPResponse_Exception |
||
643 | */ |
||
644 | public function postsnapshotsuccess(\SS_HTTPRequest $request) { |
||
645 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
646 | |||
647 | // Performs canView permission check by limiting visible projects |
||
648 | $project = $this->getCurrentProject(); |
||
649 | if (!$project) { |
||
650 | return $this->project404Response(); |
||
651 | } |
||
652 | |||
653 | if (!$project->canUploadArchive()) { |
||
654 | return new SS_HTTPResponse("Not allowed to upload", 401); |
||
655 | } |
||
656 | |||
657 | $dataArchive = DNDataArchive::get()->byId($request->param('DataArchiveID')); |
||
658 | if (!$dataArchive) { |
||
659 | return new SS_HTTPResponse("Archive not found.", 404); |
||
660 | } |
||
661 | |||
662 | if (!$dataArchive->canRestore()) { |
||
663 | throw new SS_HTTPResponse_Exception('Not allowed to restore archive', 403); |
||
664 | } |
||
665 | |||
666 | return $this->render([ |
||
667 | 'Title' => 'How to send us your Data Snapshot by post', |
||
668 | 'DataArchive' => $dataArchive, |
||
669 | 'Address' => Config::inst()->get('Deploynaut', 'snapshot_post_address'), |
||
670 | 'BackURL' => $project->Link(), |
||
671 | ]); |
||
672 | } |
||
673 | |||
674 | /** |
||
675 | * @param \SS_HTTPRequest $request |
||
676 | * @return \SS_HTTPResponse |
||
677 | */ |
||
678 | public function project(\SS_HTTPRequest $request) { |
||
679 | $this->setCurrentActionType(self::PROJECT_OVERVIEW); |
||
680 | return $this->getCustomisedViewSection('ProjectOverview', '', ['IsAdmin' => Permission::check('ADMIN')]); |
||
681 | } |
||
682 | |||
683 | /** |
||
684 | * This action will star / unstar a project for the current member |
||
685 | * |
||
686 | * @param \SS_HTTPRequest $request |
||
687 | * |
||
688 | * @return SS_HTTPResponse |
||
689 | */ |
||
690 | public function toggleprojectstar(\SS_HTTPRequest $request) { |
||
691 | $project = $this->getCurrentProject(); |
||
692 | if (!$project) { |
||
693 | return $this->project404Response(); |
||
694 | } |
||
695 | |||
696 | $member = Member::currentUser(); |
||
697 | if ($member === null) { |
||
698 | return $this->project404Response(); |
||
699 | } |
||
700 | $favProject = $member->StarredProjects() |
||
701 | ->filter('DNProjectID', $project->ID) |
||
702 | ->first(); |
||
703 | |||
704 | if ($favProject) { |
||
705 | $member->StarredProjects()->remove($favProject); |
||
706 | } else { |
||
707 | $member->StarredProjects()->add($project); |
||
708 | } |
||
709 | |||
710 | if (!$request->isAjax()) { |
||
711 | return $this->redirectBack(); |
||
712 | } |
||
713 | } |
||
714 | |||
715 | /** |
||
716 | * @param \SS_HTTPRequest $request |
||
717 | * @return \SS_HTTPResponse |
||
718 | */ |
||
719 | public function branch(\SS_HTTPRequest $request) { |
||
720 | $project = $this->getCurrentProject(); |
||
721 | if (!$project) { |
||
722 | return $this->project404Response(); |
||
723 | } |
||
724 | |||
725 | $branchName = $request->getVar('name'); |
||
726 | $branch = $project->DNBranchList()->byName($branchName); |
||
727 | if (!$branch) { |
||
728 | return new SS_HTTPResponse("Branch '" . Convert::raw2xml($branchName) . "' not found.", 404); |
||
729 | } |
||
730 | |||
731 | return $this->render([ |
||
732 | 'CurrentBranch' => $branch, |
||
733 | ]); |
||
734 | } |
||
735 | |||
736 | /** |
||
737 | * @param \SS_HTTPRequest $request |
||
738 | * @return \SS_HTTPResponse |
||
739 | */ |
||
740 | public function environment(\SS_HTTPRequest $request) { |
||
741 | // Performs canView permission check by limiting visible projects |
||
742 | $project = $this->getCurrentProject(); |
||
743 | if (!$project) { |
||
744 | return $this->project404Response(); |
||
745 | } |
||
746 | |||
747 | // Performs canView permission check by limiting visible projects |
||
748 | $env = $this->getCurrentEnvironment($project); |
||
749 | if (!$env) { |
||
750 | return $this->environment404Response(); |
||
751 | } |
||
752 | |||
753 | return $this->render([ |
||
754 | 'DNEnvironmentList' => $this->getCurrentProject()->DNEnvironmentList(), |
||
755 | 'Redeploy' => (bool) $request->getVar('redeploy') |
||
756 | ]); |
||
757 | } |
||
758 | |||
759 | /** |
||
760 | * Shows the creation log. |
||
761 | * |
||
762 | * @param \SS_HTTPRequest $request |
||
763 | * @return string |
||
764 | */ |
||
765 | public function createenv(\SS_HTTPRequest $request) { |
||
766 | $params = $request->params(); |
||
767 | if ($params['Identifier']) { |
||
768 | $record = DNCreateEnvironment::get()->byId($params['Identifier']); |
||
769 | |||
770 | if (!$record || !$record->ID) { |
||
771 | throw new SS_HTTPResponse_Exception('Create environment not found', 404); |
||
772 | } |
||
773 | if (!$record->canView()) { |
||
774 | return Security::permissionFailure(); |
||
775 | } |
||
776 | |||
777 | $project = $this->getCurrentProject(); |
||
778 | if (!$project) { |
||
779 | return $this->project404Response(); |
||
780 | } |
||
781 | |||
782 | if ($project->Name != $params['Project']) { |
||
783 | throw new LogicException("Project in URL doesn't match this creation"); |
||
784 | } |
||
785 | |||
786 | return $this->render([ |
||
787 | 'CreateEnvironment' => $record, |
||
788 | ]); |
||
789 | } |
||
790 | return $this->render(['CurrentTitle' => 'Create an environment']); |
||
791 | } |
||
792 | |||
793 | public function createenvlog(\SS_HTTPRequest $request) { |
||
794 | $params = $request->params(); |
||
795 | $env = DNCreateEnvironment::get()->byId($params['Identifier']); |
||
796 | |||
797 | if (!$env || !$env->ID) { |
||
798 | throw new SS_HTTPResponse_Exception('Log not found', 404); |
||
799 | } |
||
800 | if (!$env->canView()) { |
||
801 | return Security::permissionFailure(); |
||
802 | } |
||
803 | |||
804 | $project = $env->Project(); |
||
805 | |||
806 | if ($project->Name != $params['Project']) { |
||
807 | throw new LogicException("Project in URL doesn't match this deploy"); |
||
808 | } |
||
809 | |||
810 | $log = $env->log(); |
||
811 | if ($log->exists()) { |
||
812 | $content = $log->content(); |
||
813 | } else { |
||
814 | $content = 'Waiting for action to start'; |
||
815 | } |
||
816 | |||
817 | return $this->sendResponse($env->ResqueStatus(), $content); |
||
818 | } |
||
819 | |||
820 | /** |
||
821 | * @param \SS_HTTPRequest $request |
||
822 | * @return Form |
||
823 | */ |
||
824 | public function getCreateEnvironmentForm(\SS_HTTPRequest $request = null) { |
||
825 | $this->setCurrentActionType(self::ACTION_ENVIRONMENTS); |
||
826 | |||
827 | $project = $this->getCurrentProject(); |
||
828 | if (!$project) { |
||
829 | return $this->project404Response(); |
||
830 | } |
||
831 | |||
832 | $envType = $project->AllowedEnvironmentType; |
||
0 ignored issues
–
show
The property
AllowedEnvironmentType does not exist on object<DNProject> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. ![]() |
|||
833 | if (!$envType || !class_exists($envType)) { |
||
834 | return null; |
||
835 | } |
||
836 | |||
837 | $backend = Injector::inst()->get($envType); |
||
838 | if (!($backend instanceof EnvironmentCreateBackend)) { |
||
839 | // Only allow this for supported backends. |
||
840 | return null; |
||
841 | } |
||
842 | |||
843 | $fields = $backend->getCreateEnvironmentFields($project); |
||
844 | if (!$fields) { |
||
845 | return null; |
||
846 | } |
||
847 | |||
848 | if (!$project->canCreateEnvironments()) { |
||
849 | return new SS_HTTPResponse('Not allowed to create environments for this project', 401); |
||
850 | } |
||
851 | |||
852 | $form = Form::create( |
||
853 | $this, |
||
854 | 'CreateEnvironmentForm', |
||
855 | $fields, |
||
856 | FieldList::create( |
||
857 | FormAction::create('doCreateEnvironment', 'Create') |
||
858 | ->addExtraClass('btn') |
||
859 | ), |
||
860 | $backend->getCreateEnvironmentValidator() |
||
861 | ); |
||
862 | |||
863 | // Tweak the action so it plays well with our fake URL structure. |
||
864 | $form->setFormAction($project->Link() . '/CreateEnvironmentForm'); |
||
865 | |||
866 | return $form; |
||
867 | } |
||
868 | |||
869 | /** |
||
870 | * @param array $data |
||
871 | * @param Form $form |
||
872 | * |
||
873 | * @return bool|HTMLText|SS_HTTPResponse |
||
874 | */ |
||
875 | public function doCreateEnvironment($data, Form $form) { |
||
0 ignored issues
–
show
|
|||
876 | $this->setCurrentActionType(self::ACTION_ENVIRONMENTS); |
||
877 | |||
878 | $project = $this->getCurrentProject(); |
||
879 | if (!$project) { |
||
880 | return $this->project404Response(); |
||
881 | } |
||
882 | |||
883 | if (!$project->canCreateEnvironments()) { |
||
884 | return new SS_HTTPResponse('Not allowed to create environments for this project', 401); |
||
885 | } |
||
886 | |||
887 | // Set the environment type so we know what we're creating. |
||
888 | $data['EnvironmentType'] = $project->AllowedEnvironmentType; |
||
0 ignored issues
–
show
The property
AllowedEnvironmentType does not exist on object<DNProject> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. ![]() |
|||
889 | |||
890 | $job = DNCreateEnvironment::create(); |
||
891 | |||
892 | $job->Data = serialize($data); |
||
893 | $job->ProjectID = $project->ID; |
||
894 | $job->write(); |
||
895 | $job->start(); |
||
896 | |||
897 | return $this->redirect($project->Link('createenv') . '/' . $job->ID); |
||
898 | } |
||
899 | |||
900 | /** |
||
901 | * Get the DNData object. |
||
902 | * |
||
903 | * @return DNData |
||
904 | */ |
||
905 | public function DNData() { |
||
906 | return DNData::inst(); |
||
907 | } |
||
908 | |||
909 | /** |
||
910 | * Provide a list of all projects. |
||
911 | * |
||
912 | * @return SS_List |
||
913 | */ |
||
914 | public function DNProjectList() { |
||
915 | $memberId = Member::currentUserID(); |
||
916 | if (!$memberId) { |
||
917 | return new ArrayList(); |
||
918 | } |
||
919 | |||
920 | if (Permission::check('ADMIN')) { |
||
921 | return DNProject::get(); |
||
922 | } |
||
923 | |||
924 | $projects = Member::get()->filter('ID', $memberId) |
||
925 | ->relation('Groups') |
||
926 | ->relation('Projects'); |
||
927 | |||
928 | $this->extend('updateDNProjectList', $projects); |
||
929 | return $projects; |
||
930 | } |
||
931 | |||
932 | /** |
||
933 | * @return ArrayList |
||
934 | */ |
||
935 | public function getPlatformSpecificStrings() { |
||
936 | $strings = $this->config()->platform_specific_strings; |
||
937 | if ($strings) { |
||
938 | return new ArrayList($strings); |
||
939 | } |
||
940 | } |
||
941 | |||
942 | /** |
||
943 | * Provide a list of all starred projects for the currently logged in member |
||
944 | * |
||
945 | * @return SS_List |
||
946 | */ |
||
947 | public function getStarredProjects() { |
||
948 | $member = Member::currentUser(); |
||
949 | if ($member === null) { |
||
950 | return new ArrayList(); |
||
951 | } |
||
952 | |||
953 | $favProjects = $member->StarredProjects(); |
||
954 | |||
955 | $list = new ArrayList(); |
||
956 | foreach ($favProjects as $project) { |
||
957 | if ($project->canView($member)) { |
||
958 | $list->add($project); |
||
959 | } |
||
960 | } |
||
961 | return $list; |
||
962 | } |
||
963 | |||
964 | /** |
||
965 | * Returns top level navigation of projects. |
||
966 | * |
||
967 | * @param int $limit |
||
968 | * |
||
969 | * @return ArrayList |
||
970 | */ |
||
971 | public function Navigation($limit = 5) { |
||
972 | $navigation = new ArrayList(); |
||
973 | |||
974 | $currentProject = $this->getCurrentProject(); |
||
975 | $currentEnvironment = $this->getCurrentEnvironment(); |
||
976 | $actionType = $this->getCurrentActionType(); |
||
977 | |||
978 | $projects = $this->getStarredProjects(); |
||
979 | if ($projects->count() < 1) { |
||
980 | $projects = $this->DNProjectList(); |
||
981 | } else { |
||
982 | $limit = -1; |
||
983 | } |
||
984 | |||
985 | if ($projects->count() > 0) { |
||
986 | $activeProject = false; |
||
987 | |||
988 | if ($limit > 0) { |
||
989 | $limitedProjects = $projects->limit($limit); |
||
990 | } else { |
||
991 | $limitedProjects = $projects; |
||
992 | } |
||
993 | |||
994 | foreach ($limitedProjects as $project) { |
||
995 | $isActive = $currentProject && $currentProject->ID == $project->ID; |
||
996 | if ($isActive) { |
||
997 | $activeProject = true; |
||
998 | } |
||
999 | |||
1000 | $isCurrentEnvironment = false; |
||
1001 | if ($project && $currentEnvironment) { |
||
1002 | $isCurrentEnvironment = (bool) $project->DNEnvironmentList()->find('ID', $currentEnvironment->ID); |
||
1003 | } |
||
1004 | |||
1005 | $navigation->push([ |
||
1006 | 'Project' => $project, |
||
1007 | 'IsCurrentEnvironment' => $isCurrentEnvironment, |
||
1008 | 'IsActive' => $currentProject && $currentProject->ID == $project->ID, |
||
1009 | 'IsOverview' => $actionType == self::PROJECT_OVERVIEW && !$isCurrentEnvironment && $currentProject->ID == $project->ID |
||
0 ignored issues
–
show
|
|||
1010 | ]); |
||
1011 | } |
||
1012 | |||
1013 | // Ensure the current project is in the list |
||
1014 | if (!$activeProject && $currentProject) { |
||
1015 | $navigation->unshift([ |
||
1016 | 'Project' => $currentProject, |
||
1017 | 'IsActive' => true, |
||
1018 | 'IsCurrentEnvironment' => $currentEnvironment, |
||
1019 | 'IsOverview' => $actionType == self::PROJECT_OVERVIEW && !$currentEnvironment |
||
1020 | ]); |
||
1021 | if ($limit > 0 && $navigation->count() > $limit) { |
||
1022 | $navigation->pop(); |
||
1023 | } |
||
1024 | } |
||
1025 | } |
||
1026 | |||
1027 | return $navigation; |
||
1028 | } |
||
1029 | |||
1030 | /** |
||
1031 | * Construct the deployment form |
||
1032 | * |
||
1033 | * @deprecated 2.0.0 - moved to DeployDispatcher |
||
1034 | * |
||
1035 | * @return Form |
||
1036 | */ |
||
1037 | public function getDeployForm($request = null) { |
||
1038 | |||
1039 | // Performs canView permission check by limiting visible projects |
||
1040 | $project = $this->getCurrentProject(); |
||
1041 | if (!$project) { |
||
1042 | return $this->project404Response(); |
||
1043 | } |
||
1044 | |||
1045 | // Performs canView permission check by limiting visible projects |
||
1046 | $environment = $this->getCurrentEnvironment($project); |
||
1047 | if (!$environment) { |
||
1048 | return $this->environment404Response(); |
||
1049 | } |
||
1050 | |||
1051 | if (!$environment->canDeploy()) { |
||
1052 | return new SS_HTTPResponse("Not allowed to deploy", 401); |
||
1053 | } |
||
1054 | |||
1055 | // Generate the form |
||
1056 | $form = new DeployForm($this, 'DeployForm', $environment, $project); |
||
0 ignored issues
–
show
The class
DeployForm has been deprecated with message: 2.0.0 - moved to Dispatchers and frontend Form for generating deployments from a specified commit
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead. ![]() |
|||
1057 | |||
1058 | // If this is an ajax request we don't want to submit the form - we just want to retrieve the markup. |
||
1059 | if ( |
||
1060 | $request && |
||
1061 | !$request->requestVar('action_showDeploySummary') && |
||
1062 | $this->getRequest()->isAjax() && |
||
1063 | $this->getRequest()->isGET() |
||
1064 | ) { |
||
1065 | // We can just use the URL we're accessing |
||
1066 | $form->setFormAction($this->getRequest()->getURL()); |
||
1067 | |||
1068 | $body = json_encode(['Content' => $form->forAjaxTemplate()->forTemplate()]); |
||
1069 | $this->getResponse()->addHeader('Content-Type', 'application/json'); |
||
1070 | $this->getResponse()->setBody($body); |
||
1071 | return $body; |
||
1072 | } |
||
1073 | |||
1074 | $form->setFormAction($this->getRequest()->getURL() . '/DeployForm'); |
||
1075 | return $form; |
||
1076 | } |
||
1077 | |||
1078 | /** |
||
1079 | * @deprecated 2.0.0 - moved to GitDispatcher |
||
1080 | * |
||
1081 | * @param \SS_HTTPRequest $request |
||
1082 | * |
||
1083 | * @return SS_HTTPResponse|string |
||
1084 | */ |
||
1085 | public function gitRevisions(\SS_HTTPRequest $request) { |
||
1086 | |||
1087 | // Performs canView permission check by limiting visible projects |
||
1088 | $project = $this->getCurrentProject(); |
||
1089 | if (!$project) { |
||
1090 | return $this->project404Response(); |
||
1091 | } |
||
1092 | |||
1093 | // Performs canView permission check by limiting visible projects |
||
1094 | $env = $this->getCurrentEnvironment($project); |
||
1095 | if (!$env) { |
||
1096 | return $this->environment404Response(); |
||
1097 | } |
||
1098 | |||
1099 | $options = []; |
||
1100 | foreach ($env->getSupportedOptions() as $option) { |
||
1101 | $options[] = [ |
||
1102 | 'name' => $option->getName(), |
||
1103 | 'title' => $option->getTitle(), |
||
1104 | 'defaultValue' => $option->getDefaultValue() |
||
1105 | ]; |
||
1106 | } |
||
1107 | |||
1108 | $tabs = []; |
||
1109 | $id = 0; |
||
1110 | $data = [ |
||
1111 | 'id' => ++$id, |
||
1112 | 'name' => 'Deploy the latest version of a branch', |
||
1113 | 'field_type' => 'dropdown', |
||
1114 | 'field_label' => 'Choose a branch', |
||
1115 | 'field_id' => 'branch', |
||
1116 | 'field_data' => [], |
||
1117 | 'options' => $options |
||
1118 | ]; |
||
1119 | View Code Duplication | foreach ($project->DNBranchList() as $branch) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
1120 | $sha = $branch->SHA(); |
||
1121 | $name = $branch->Name(); |
||
1122 | $branchValue = sprintf("%s (%s, %s old)", |
||
1123 | $name, |
||
1124 | substr($sha, 0, 8), |
||
1125 | $branch->LastUpdated()->TimeDiff() |
||
1126 | ); |
||
1127 | $data['field_data'][] = [ |
||
1128 | 'id' => $sha, |
||
1129 | 'text' => $branchValue, |
||
1130 | 'branch_name' => $name // the raw branch name, not including the time etc |
||
1131 | ]; |
||
1132 | } |
||
1133 | $tabs[] = $data; |
||
1134 | |||
1135 | $data = [ |
||
1136 | 'id' => ++$id, |
||
1137 | 'name' => 'Deploy a tagged release', |
||
1138 | 'field_type' => 'dropdown', |
||
1139 | 'field_label' => 'Choose a tag', |
||
1140 | 'field_id' => 'tag', |
||
1141 | 'field_data' => [], |
||
1142 | 'options' => $options |
||
1143 | ]; |
||
1144 | |||
1145 | View Code Duplication | foreach ($project->DNTagList()->setLimit(null) as $tag) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
1146 | $name = $tag->Name(); |
||
1147 | $data['field_data'][] = [ |
||
1148 | 'id' => $tag->SHA(), |
||
1149 | 'text' => sprintf("%s", $name) |
||
1150 | ]; |
||
1151 | } |
||
1152 | |||
1153 | // show newest tags first. |
||
1154 | $data['field_data'] = array_reverse($data['field_data']); |
||
1155 | |||
1156 | $tabs[] = $data; |
||
1157 | |||
1158 | // Past deployments |
||
1159 | $data = [ |
||
1160 | 'id' => ++$id, |
||
1161 | 'name' => 'Redeploy a release that was previously deployed (to any environment)', |
||
1162 | 'field_type' => 'dropdown', |
||
1163 | 'field_label' => 'Choose a previously deployed release', |
||
1164 | 'field_id' => 'release', |
||
1165 | 'field_data' => [], |
||
1166 | 'options' => $options |
||
1167 | ]; |
||
1168 | // We are aiming at the format: |
||
1169 | // [{text: 'optgroup text', children: [{id: '<sha>', text: '<inner text>'}]}] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
55% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
1170 | $redeploy = []; |
||
1171 | View Code Duplication | foreach ($project->DNEnvironmentList() as $dnEnvironment) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
1172 | $envName = $dnEnvironment->Name; |
||
1173 | $perEnvDeploys = []; |
||
1174 | |||
1175 | foreach ($dnEnvironment->DeployHistory()->filter('State', \DNDeployment::STATE_COMPLETED) as $deploy) { |
||
1176 | $sha = $deploy->SHA; |
||
1177 | |||
1178 | // Check if exists to make sure the newest deployment date is used. |
||
1179 | if (!isset($perEnvDeploys[$sha])) { |
||
1180 | $pastValue = sprintf("%s (deployed %s)", |
||
1181 | substr($sha, 0, 8), |
||
1182 | $deploy->obj('LastEdited')->Ago() |
||
1183 | ); |
||
1184 | $perEnvDeploys[$sha] = [ |
||
1185 | 'id' => $sha, |
||
1186 | 'text' => $pastValue |
||
1187 | ]; |
||
1188 | } |
||
1189 | } |
||
1190 | |||
1191 | if (!empty($perEnvDeploys)) { |
||
1192 | $redeploy[$envName] = array_values($perEnvDeploys); |
||
1193 | } |
||
1194 | } |
||
1195 | // Convert the array to the frontend format (i.e. keyed to regular array) |
||
1196 | foreach ($redeploy as $name => $descr) { |
||
1197 | $data['field_data'][] = ['text' => $name, 'children' => $descr]; |
||
1198 | } |
||
1199 | $tabs[] = $data; |
||
1200 | |||
1201 | $data = [ |
||
1202 | 'id' => ++$id, |
||
1203 | 'name' => 'Deploy a specific SHA', |
||
1204 | 'field_type' => 'textfield', |
||
1205 | 'field_label' => 'Choose a SHA', |
||
1206 | 'field_id' => 'SHA', |
||
1207 | 'field_data' => [], |
||
1208 | 'options' => $options |
||
1209 | ]; |
||
1210 | $tabs[] = $data; |
||
1211 | |||
1212 | // get the last time git fetch was run |
||
1213 | $lastFetched = 'never'; |
||
1214 | $fetch = DNGitFetch::get() |
||
1215 | ->filter([ |
||
1216 | 'ProjectID' => $project->ID, |
||
1217 | 'Status' => 'Finished' |
||
1218 | ]) |
||
1219 | ->sort('LastEdited', 'DESC') |
||
1220 | ->first(); |
||
1221 | if ($fetch) { |
||
1222 | $lastFetched = $fetch->dbObject('LastEdited')->Ago(); |
||
1223 | } |
||
1224 | |||
1225 | $data = [ |
||
1226 | 'Tabs' => $tabs, |
||
1227 | 'last_fetched' => $lastFetched |
||
1228 | ]; |
||
1229 | |||
1230 | $this->applyRedeploy($request, $data); |
||
1231 | |||
1232 | return json_encode($data, JSON_PRETTY_PRINT); |
||
1233 | } |
||
1234 | |||
1235 | /** |
||
1236 | * @deprecated 2.0.0 - moved to DeployDispatcher |
||
1237 | * |
||
1238 | * @param \SS_HTTPRequest $request |
||
1239 | * |
||
1240 | * @return string |
||
1241 | */ |
||
1242 | public function deploySummary(\SS_HTTPRequest $request) { |
||
1243 | |||
1244 | // Performs canView permission check by limiting visible projects |
||
1245 | $project = $this->getCurrentProject(); |
||
1246 | if (!$project) { |
||
1247 | return $this->project404Response(); |
||
1248 | } |
||
1249 | |||
1250 | // Performs canView permission check by limiting visible projects |
||
1251 | $environment = $this->getCurrentEnvironment($project); |
||
1252 | if (!$environment) { |
||
1253 | return $this->environment404Response(); |
||
1254 | } |
||
1255 | |||
1256 | // Plan the deployment. |
||
1257 | $strategy = $environment->getDeployStrategy($request); |
||
1258 | $data = $strategy->toArray(); |
||
1259 | |||
1260 | // Add in a URL for comparing from->to code changes. Ensure that we have |
||
1261 | // two proper 40 character SHAs, otherwise we can't show the compare link. |
||
1262 | $interface = $project->getRepositoryInterface(); |
||
1263 | if ( |
||
1264 | !empty($interface) && !empty($interface->URL) |
||
1265 | && !empty($data['changes']['Code version']['from']) |
||
1266 | && strlen($data['changes']['Code version']['from']) == '40' |
||
1267 | && !empty($data['changes']['Code version']['to']) |
||
1268 | && strlen($data['changes']['Code version']['to']) == '40' |
||
1269 | ) { |
||
1270 | $compareurl = sprintf( |
||
1271 | '%s/compare/%s...%s', |
||
1272 | $interface->URL, |
||
1273 | $data['changes']['Code version']['from'], |
||
1274 | $data['changes']['Code version']['to'] |
||
1275 | ); |
||
1276 | $data['changes']['Code version']['compareUrl'] = $compareurl; |
||
1277 | } |
||
1278 | |||
1279 | // Append json to response |
||
1280 | $token = SecurityToken::inst(); |
||
1281 | $data['SecurityID'] = $token->getValue(); |
||
1282 | |||
1283 | $this->extend('updateDeploySummary', $data); |
||
1284 | |||
1285 | return json_encode($data); |
||
1286 | } |
||
1287 | |||
1288 | /** |
||
1289 | * Deployment form submission handler. |
||
1290 | * |
||
1291 | * @deprecated 2.0.0 - moved to DeployDispatcher |
||
1292 | * |
||
1293 | * Initiate a DNDeployment record and redirect to it for status polling |
||
1294 | * |
||
1295 | * @param \SS_HTTPRequest $request |
||
1296 | * |
||
1297 | * @return SS_HTTPResponse |
||
1298 | * @throws ValidationException |
||
1299 | * @throws null |
||
1300 | */ |
||
1301 | public function startDeploy(\SS_HTTPRequest $request) { |
||
1302 | |||
1303 | $token = SecurityToken::inst(); |
||
1304 | |||
1305 | // Ensure the submitted token has a value |
||
1306 | $submittedToken = $request->postVar(\Dispatcher::SECURITY_TOKEN_NAME); |
||
1307 | if (!$submittedToken) { |
||
1308 | return false; |
||
1309 | } |
||
1310 | // Do the actual check. |
||
1311 | $check = $token->check($submittedToken); |
||
1312 | // Ensure the CSRF Token is correct |
||
1313 | if (!$check) { |
||
1314 | // CSRF token didn't match |
||
1315 | return $this->httpError(400, 'Bad Request'); |
||
1316 | } |
||
1317 | |||
1318 | // Performs canView permission check by limiting visible projects |
||
1319 | $project = $this->getCurrentProject(); |
||
1320 | if (!$project) { |
||
1321 | return $this->project404Response(); |
||
1322 | } |
||
1323 | |||
1324 | // Performs canView permission check by limiting visible projects |
||
1325 | $environment = $this->getCurrentEnvironment($project); |
||
1326 | if (!$environment) { |
||
1327 | return $this->environment404Response(); |
||
1328 | } |
||
1329 | |||
1330 | // Initiate the deployment |
||
1331 | // The extension point should pass in: Project, Environment, SelectRelease, buildName |
||
1332 | $this->extend('doDeploy', $project, $environment, $buildName, $data); |
||
1333 | |||
1334 | // Start the deployment based on the approved strategy. |
||
1335 | $strategy = new DeploymentStrategy($environment); |
||
1336 | $strategy->fromArray($request->requestVar('strategy')); |
||
1337 | $deployment = $strategy->createDeployment(); |
||
1338 | // Bypass approval by going straight to Queued. |
||
1339 | $deployment->getMachine()->apply(DNDeployment::TR_QUEUE); |
||
1340 | |||
1341 | return json_encode([ |
||
1342 | 'url' => Director::absoluteBaseURL() . $deployment->Link() |
||
1343 | ], JSON_PRETTY_PRINT); |
||
1344 | } |
||
1345 | |||
1346 | /** |
||
1347 | * @deprecated 2.0.0 - moved to DeployDispatcher |
||
1348 | * |
||
1349 | * Action - Do the actual deploy |
||
1350 | * |
||
1351 | * @param \SS_HTTPRequest $request |
||
1352 | * |
||
1353 | * @return SS_HTTPResponse|string |
||
1354 | * @throws SS_HTTPResponse_Exception |
||
1355 | */ |
||
1356 | public function deploy(\SS_HTTPRequest $request) { |
||
1357 | $params = $request->params(); |
||
1358 | $deployment = DNDeployment::get()->byId($params['Identifier']); |
||
1359 | |||
1360 | if (!$deployment || !$deployment->ID) { |
||
1361 | throw new SS_HTTPResponse_Exception('Deployment not found', 404); |
||
1362 | } |
||
1363 | if (!$deployment->canView()) { |
||
1364 | return Security::permissionFailure(); |
||
1365 | } |
||
1366 | |||
1367 | $environment = $deployment->Environment(); |
||
1368 | $project = $environment->Project(); |
||
1369 | |||
1370 | if ($environment->Name != $params['Environment']) { |
||
1371 | throw new LogicException("Environment in URL doesn't match this deploy"); |
||
1372 | } |
||
1373 | if ($project->Name != $params['Project']) { |
||
1374 | throw new LogicException("Project in URL doesn't match this deploy"); |
||
1375 | } |
||
1376 | |||
1377 | return $this->render([ |
||
1378 | 'Deployment' => $deployment, |
||
1379 | ]); |
||
1380 | } |
||
1381 | |||
1382 | /** |
||
1383 | * @deprecated 2.0.0 - moved to DeployDispatcher |
||
1384 | * |
||
1385 | * Action - Get the latest deploy log |
||
1386 | * |
||
1387 | * @param \SS_HTTPRequest $request |
||
1388 | * |
||
1389 | * @return string |
||
1390 | * @throws SS_HTTPResponse_Exception |
||
1391 | */ |
||
1392 | public function deploylog(\SS_HTTPRequest $request) { |
||
1393 | $params = $request->params(); |
||
1394 | $deployment = DNDeployment::get()->byId($params['Identifier']); |
||
1395 | |||
1396 | if (!$deployment || !$deployment->ID) { |
||
1397 | throw new SS_HTTPResponse_Exception('Deployment not found', 404); |
||
1398 | } |
||
1399 | if (!$deployment->canView()) { |
||
1400 | return Security::permissionFailure(); |
||
1401 | } |
||
1402 | |||
1403 | $environment = $deployment->Environment(); |
||
1404 | $project = $environment->Project(); |
||
1405 | |||
1406 | if ($environment->Name != $params['Environment']) { |
||
1407 | throw new LogicException("Environment in URL doesn't match this deploy"); |
||
1408 | } |
||
1409 | if ($project->Name != $params['Project']) { |
||
1410 | throw new LogicException("Project in URL doesn't match this deploy"); |
||
1411 | } |
||
1412 | |||
1413 | $log = $deployment->log(); |
||
1414 | if ($log->exists()) { |
||
1415 | $content = $log->content(); |
||
1416 | } else { |
||
1417 | $content = 'Waiting for action to start'; |
||
1418 | } |
||
1419 | |||
1420 | return $this->sendResponse($deployment->ResqueStatus(), $content); |
||
1421 | } |
||
1422 | |||
1423 | /** |
||
1424 | * @deprecated 2.0.0 - moved to DeployDispatcher |
||
1425 | * |
||
1426 | * @param \SS_HTTPRequest $request |
||
1427 | * |
||
1428 | * @return string |
||
1429 | * @throws SS_HTTPResponse_Exception |
||
1430 | */ |
||
1431 | public function abortDeploy(\SS_HTTPRequest $request) { |
||
1432 | $params = $request->params(); |
||
1433 | $deployment = DNDeployment::get()->byId($params['Identifier']); |
||
1434 | |||
1435 | if (!$deployment || !$deployment->ID) { |
||
1436 | throw new SS_HTTPResponse_Exception('Deployment not found', 404); |
||
1437 | } |
||
1438 | if (!$deployment->canView()) { |
||
1439 | return Security::permissionFailure(); |
||
1440 | } |
||
1441 | |||
1442 | // For now restrict to ADMINs only. |
||
1443 | if (!Permission::check('ADMIN')) { |
||
1444 | return Security::permissionFailure(); |
||
1445 | } |
||
1446 | |||
1447 | $environment = $deployment->Environment(); |
||
1448 | $project = $environment->Project(); |
||
1449 | |||
1450 | if ($environment->Name != $params['Environment']) { |
||
1451 | throw new LogicException("Environment in URL doesn't match this deploy"); |
||
1452 | } |
||
1453 | if ($project->Name != $params['Project']) { |
||
1454 | throw new LogicException("Project in URL doesn't match this deploy"); |
||
1455 | } |
||
1456 | |||
1457 | if (!in_array($deployment->Status, ['Queued', 'Deploying', 'Aborting'])) { |
||
1458 | throw new LogicException(sprintf("Cannot abort from %s state.", $deployment->Status)); |
||
1459 | } |
||
1460 | |||
1461 | $deployment->getMachine()->apply(DNDeployment::TR_ABORT); |
||
1462 | |||
1463 | return $this->sendResponse($deployment->ResqueStatus(), []); |
||
0 ignored issues
–
show
array() is of type array , but the function expects a string .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
1464 | } |
||
1465 | |||
1466 | /** |
||
1467 | * @param \SS_HTTPRequest|null $request |
||
1468 | * |
||
1469 | * @return Form |
||
1470 | */ |
||
1471 | public function getDataTransferForm(\SS_HTTPRequest $request = null) { |
||
1472 | // Performs canView permission check by limiting visible projects |
||
1473 | $envs = $this->getCurrentProject()->DNEnvironmentList()->filterByCallback(function ($item) { |
||
1474 | return $item->canBackup(); |
||
1475 | }); |
||
1476 | |||
1477 | if (!$envs) { |
||
1478 | return $this->environment404Response(); |
||
1479 | } |
||
1480 | |||
1481 | $items = []; |
||
1482 | $disabledEnvironments = []; |
||
1483 | View Code Duplication | foreach($envs as $env) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
1484 | $items[$env->ID] = $env->Title; |
||
1485 | if ($env->CurrentBuild() === false) { |
||
1486 | $items[$env->ID] = sprintf("%s - requires initial deployment", $env->Title); |
||
1487 | $disabledEnvironments[] = $env->ID; |
||
1488 | } |
||
1489 | } |
||
1490 | |||
1491 | $envsField = DropdownField::create('EnvironmentID', 'Environment', $items) |
||
1492 | ->setEmptyString('Select an environment'); |
||
1493 | $envsField->setDisabledItems($disabledEnvironments); |
||
1494 | |||
1495 | $formAction = FormAction::create('doDataTransfer', 'Create') |
||
1496 | ->addExtraClass('btn'); |
||
1497 | |||
1498 | if (count($disabledEnvironments) === $envs->count()) { |
||
1499 | $formAction->setDisabled(true); |
||
1500 | } |
||
1501 | |||
1502 | // Allow the _resampled dir to be included if we are a Rainforest Env |
||
1503 | if ($this->getCurrentProject()->DNEnvironmentList()->first() instanceof RainforestEnvironment) { |
||
0 ignored issues
–
show
The class
RainforestEnvironment does not exist. Did you forget a USE statement, or did you not list all dependencies?
This error could be the result of: 1. Missing dependenciesPHP Analyzer uses your Are you sure this class is defined by one of your dependencies, or did you maybe
not list a dependency in either the 2. Missing use statementPHP does not complain about undefined classes in if ($x instanceof DoesNotExist) {
// Do something.
}
If you have not tested against this specific condition, such errors might go unnoticed. ![]() |
|||
1504 | $fields = FieldList::create( |
||
1505 | HiddenField::create('Direction', null, 'get'), |
||
1506 | $envsField, |
||
1507 | DropdownField::create('Mode', 'Transfer', DNDataArchive::get_mode_map()), |
||
1508 | CheckboxField::create('IncludeResampled', 'Include Resampled Images Directory? (e.g. for total content migration)') |
||
1509 | ); |
||
1510 | } else { |
||
1511 | $fields = FieldList::create( |
||
1512 | HiddenField::create('Direction', null, 'get'), |
||
1513 | $envsField, |
||
1514 | DropdownField::create('Mode', 'Transfer', DNDataArchive::get_mode_map()) |
||
1515 | ); |
||
1516 | } |
||
1517 | |||
1518 | $form = Form::create( |
||
1519 | $this, |
||
1520 | 'DataTransferForm', |
||
1521 | $fields, |
||
1522 | FieldList::create($formAction) |
||
1523 | ); |
||
1524 | $form->setFormAction($this->getRequest()->getURL() . '/DataTransferForm'); |
||
1525 | |||
1526 | return $form; |
||
1527 | } |
||
1528 | |||
1529 | /** |
||
1530 | * @param array $data |
||
1531 | * @param Form $form |
||
1532 | * |
||
1533 | * @return SS_HTTPResponse |
||
1534 | * @throws SS_HTTPResponse_Exception |
||
1535 | */ |
||
1536 | public function doDataTransfer($data, Form $form) { |
||
0 ignored issues
–
show
|
|||
1537 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
1538 | |||
1539 | // Performs canView permission check by limiting visible projects |
||
1540 | $project = $this->getCurrentProject(); |
||
1541 | if (!$project) { |
||
1542 | return $this->project404Response(); |
||
1543 | } |
||
1544 | |||
1545 | $dataArchive = null; |
||
1546 | |||
1547 | // Validate direction. |
||
1548 | if ($data['Direction'] == 'get') { |
||
1549 | $validEnvs = $this->getCurrentProject()->DNEnvironmentList() |
||
1550 | ->filterByCallback(function ($item) { |
||
1551 | return $item->canBackup(); |
||
1552 | }); |
||
1553 | } else if ($data['Direction'] == 'push') { |
||
1554 | $validEnvs = $this->getCurrentProject()->DNEnvironmentList() |
||
1555 | ->filterByCallback(function ($item) { |
||
1556 | return $item->canRestore(); |
||
1557 | }); |
||
1558 | } else { |
||
1559 | throw new LogicException('Invalid direction'); |
||
1560 | } |
||
1561 | |||
1562 | // Validate $data['EnvironmentID'] by checking against $validEnvs. |
||
1563 | $environment = $validEnvs->find('ID', $data['EnvironmentID']); |
||
1564 | if (!$environment) { |
||
1565 | throw new LogicException('Invalid environment'); |
||
1566 | } |
||
1567 | |||
1568 | $this->validateSnapshotMode($data['Mode']); |
||
1569 | |||
1570 | // Only 'push' direction is allowed an association with an existing archive. |
||
1571 | if ( |
||
1572 | $data['Direction'] == 'push' |
||
1573 | && isset($data['DataArchiveID']) |
||
1574 | && is_numeric($data['DataArchiveID']) |
||
1575 | ) { |
||
1576 | $dataArchive = DNDataArchive::get()->byId($data['DataArchiveID']); |
||
1577 | if (!$dataArchive) { |
||
1578 | throw new LogicException('Invalid data archive'); |
||
1579 | } |
||
1580 | |||
1581 | if (!$dataArchive->canDownload()) { |
||
1582 | throw new SS_HTTPResponse_Exception('Not allowed to access archive', 403); |
||
1583 | } |
||
1584 | } |
||
1585 | |||
1586 | $transfer = DNDataTransfer::create(); |
||
1587 | $transfer->EnvironmentID = $environment->ID; |
||
1588 | $transfer->Direction = $data['Direction']; |
||
1589 | $transfer->Mode = $data['Mode']; |
||
1590 | $transfer->DataArchiveID = $dataArchive ? $dataArchive->ID : null; |
||
1591 | $transfer->IncludeResampled = $data['IncludeResampled']; |
||
0 ignored issues
–
show
The property
IncludeResampled does not exist on object<DNDataTransfer> . Since you implemented __set , maybe consider adding a @property annotation.
Since your code implements the magic setter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
Since the property has write access only, you can use the @property-write annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. ![]() |
|||
1592 | if ($data['Direction'] == 'push') { |
||
1593 | $transfer->setBackupBeforePush(!empty($data['BackupBeforePush'])); |
||
1594 | } |
||
1595 | $transfer->write(); |
||
1596 | $transfer->start(); |
||
1597 | |||
1598 | return $this->redirect($transfer->Link()); |
||
1599 | } |
||
1600 | |||
1601 | /** |
||
1602 | * View into the log for a {@link DNDataTransfer}. |
||
1603 | * |
||
1604 | * @param \SS_HTTPRequest $request |
||
1605 | * |
||
1606 | * @return SS_HTTPResponse|string |
||
1607 | * @throws SS_HTTPResponse_Exception |
||
1608 | */ |
||
1609 | public function transfer(\SS_HTTPRequest $request) { |
||
1610 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
1611 | |||
1612 | $params = $request->params(); |
||
1613 | $transfer = DNDataTransfer::get()->byId($params['Identifier']); |
||
1614 | |||
1615 | if (!$transfer || !$transfer->ID) { |
||
1616 | throw new SS_HTTPResponse_Exception('Transfer not found', 404); |
||
1617 | } |
||
1618 | if (!$transfer->canView()) { |
||
1619 | return Security::permissionFailure(); |
||
1620 | } |
||
1621 | |||
1622 | $environment = $transfer->Environment(); |
||
1623 | $project = $environment->Project(); |
||
1624 | |||
1625 | if ($project->Name != $params['Project']) { |
||
1626 | throw new LogicException("Project in URL doesn't match this deploy"); |
||
1627 | } |
||
1628 | |||
1629 | return $this->render([ |
||
1630 | 'CurrentTransfer' => $transfer, |
||
1631 | 'SnapshotsSection' => 1, |
||
1632 | ]); |
||
1633 | } |
||
1634 | |||
1635 | /** |
||
1636 | * Action - Get the latest deploy log |
||
1637 | * |
||
1638 | * @param \SS_HTTPRequest $request |
||
1639 | * |
||
1640 | * @return string |
||
1641 | * @throws SS_HTTPResponse_Exception |
||
1642 | */ |
||
1643 | public function transferlog(\SS_HTTPRequest $request) { |
||
1644 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
1645 | |||
1646 | $params = $request->params(); |
||
1647 | $transfer = DNDataTransfer::get()->byId($params['Identifier']); |
||
1648 | |||
1649 | if (!$transfer || !$transfer->ID) { |
||
1650 | throw new SS_HTTPResponse_Exception('Transfer not found', 404); |
||
1651 | } |
||
1652 | if (!$transfer->canView()) { |
||
1653 | return Security::permissionFailure(); |
||
1654 | } |
||
1655 | |||
1656 | $environment = $transfer->Environment(); |
||
1657 | $project = $environment->Project(); |
||
1658 | |||
1659 | if ($project->Name != $params['Project']) { |
||
1660 | throw new LogicException("Project in URL doesn't match this deploy"); |
||
1661 | } |
||
1662 | |||
1663 | $log = $transfer->log(); |
||
1664 | if ($log->exists()) { |
||
1665 | $content = $log->content(); |
||
1666 | } else { |
||
1667 | $content = 'Waiting for action to start'; |
||
1668 | } |
||
1669 | |||
1670 | return $this->sendResponse($transfer->ResqueStatus(), $content); |
||
1671 | } |
||
1672 | |||
1673 | /** |
||
1674 | * Note: Submits to the same action as {@link getDataTransferForm()}, |
||
1675 | * but with a Direction=push and an archive reference. |
||
1676 | * |
||
1677 | * @param \SS_HTTPRequest $request |
||
1678 | * @param \DNDataArchive|null $dataArchive Only set when method is called manually in {@link restore()}, |
||
1679 | * otherwise the state is inferred from the request data. |
||
1680 | * @return Form |
||
1681 | */ |
||
1682 | public function getDataTransferRestoreForm(\SS_HTTPRequest $request, \DNDataArchive $dataArchive = null) { |
||
1683 | $dataArchive = $dataArchive ? $dataArchive : DNDataArchive::get()->byId($request->requestVar('DataArchiveID')); |
||
1684 | |||
1685 | // Performs canView permission check by limiting visible projects |
||
1686 | $project = $this->getCurrentProject(); |
||
1687 | $envs = $project->DNEnvironmentList()->filterByCallback(function ($item) { |
||
1688 | return $item->canRestore(); |
||
1689 | }); |
||
1690 | |||
1691 | if (!$envs) { |
||
1692 | return $this->environment404Response(); |
||
1693 | } |
||
1694 | |||
1695 | $modesMap = []; |
||
1696 | if (in_array($dataArchive->Mode, ['all'])) { |
||
1697 | $modesMap['all'] = 'Database and Assets'; |
||
1698 | }; |
||
1699 | if (in_array($dataArchive->Mode, ['all', 'db'])) { |
||
1700 | $modesMap['db'] = 'Database only'; |
||
1701 | }; |
||
1702 | if (in_array($dataArchive->Mode, ['all', 'assets'])) { |
||
1703 | $modesMap['assets'] = 'Assets only'; |
||
1704 | }; |
||
1705 | |||
1706 | $alertMessage = '<div class="alert alert-warning"><strong>Warning:</strong> ' |
||
1707 | . 'This restore will overwrite the data on the chosen environment below</div>'; |
||
1708 | |||
1709 | |||
1710 | $items = []; |
||
1711 | $disabledEnvironments = []; |
||
1712 | View Code Duplication | foreach($envs as $env) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
1713 | $items[$env->ID] = $env->Title; |
||
1714 | if ($env->CurrentBuild() === false) { |
||
1715 | $items[$env->ID] = sprintf("%s - requires initial deployment", $env->Title); |
||
1716 | $disabledEnvironments[] = $env->ID; |
||
1717 | } |
||
1718 | } |
||
1719 | |||
1720 | $envsField = DropdownField::create('EnvironmentID', 'Environment', $items) |
||
1721 | ->setEmptyString('Select an environment'); |
||
1722 | $envsField->setDisabledItems($disabledEnvironments); |
||
1723 | $formAction = FormAction::create('doDataTransfer', 'Restore Data')->addExtraClass('btn'); |
||
1724 | |||
1725 | if (count($disabledEnvironments) == $envs->count()) { |
||
1726 | $formAction->setDisabled(true); |
||
1727 | } |
||
1728 | |||
1729 | $form = Form::create( |
||
1730 | $this, |
||
1731 | 'DataTransferRestoreForm', |
||
1732 | FieldList::create( |
||
1733 | HiddenField::create('DataArchiveID', null, $dataArchive->ID), |
||
1734 | HiddenField::create('Direction', null, 'push'), |
||
1735 | LiteralField::create('Warning', $alertMessage), |
||
1736 | $envsField, |
||
1737 | DropdownField::create('Mode', 'Transfer', $modesMap), |
||
1738 | CheckboxField::create('BackupBeforePush', 'Backup existing data', '1') |
||
1739 | ), |
||
1740 | FieldList::create($formAction) |
||
1741 | ); |
||
1742 | $form->setFormAction($project->Link() . '/DataTransferRestoreForm'); |
||
1743 | |||
1744 | return $form; |
||
1745 | } |
||
1746 | |||
1747 | /** |
||
1748 | * View a form to restore a specific {@link DataArchive}. |
||
1749 | * Permission checks are handled in {@link DataArchives()}. |
||
1750 | * Submissions are handled through {@link doDataTransfer()}, same as backup operations. |
||
1751 | * |
||
1752 | * @param \SS_HTTPRequest $request |
||
1753 | * |
||
1754 | * @return HTMLText |
||
1755 | * @throws SS_HTTPResponse_Exception |
||
1756 | */ |
||
1757 | View Code Duplication | public function restoresnapshot(\SS_HTTPRequest $request) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
1758 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
1759 | |||
1760 | /** @var DNDataArchive $dataArchive */ |
||
1761 | $dataArchive = DNDataArchive::get()->byId($request->param('DataArchiveID')); |
||
1762 | |||
1763 | if (!$dataArchive) { |
||
1764 | throw new SS_HTTPResponse_Exception('Archive not found', 404); |
||
1765 | } |
||
1766 | |||
1767 | // We check for canDownload because that implies access to the data. |
||
1768 | // canRestore is later checked on the actual restore action per environment. |
||
1769 | if (!$dataArchive->canDownload()) { |
||
1770 | throw new SS_HTTPResponse_Exception('Not allowed to access archive', 403); |
||
1771 | } |
||
1772 | |||
1773 | $form = $this->getDataTransferRestoreForm($this->request, $dataArchive); |
||
1774 | |||
1775 | // View currently only available via ajax |
||
1776 | return $form->forTemplate(); |
||
1777 | } |
||
1778 | |||
1779 | /** |
||
1780 | * View a form to delete a specific {@link DataArchive}. |
||
1781 | * Permission checks are handled in {@link DataArchives()}. |
||
1782 | * Submissions are handled through {@link doDelete()}. |
||
1783 | * |
||
1784 | * @param \SS_HTTPRequest $request |
||
1785 | * |
||
1786 | * @return HTMLText |
||
1787 | * @throws SS_HTTPResponse_Exception |
||
1788 | */ |
||
1789 | View Code Duplication | public function deletesnapshot(\SS_HTTPRequest $request) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
1790 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
1791 | |||
1792 | /** @var DNDataArchive $dataArchive */ |
||
1793 | $dataArchive = DNDataArchive::get()->byId($request->param('DataArchiveID')); |
||
1794 | |||
1795 | if (!$dataArchive) { |
||
1796 | throw new SS_HTTPResponse_Exception('Archive not found', 404); |
||
1797 | } |
||
1798 | |||
1799 | if (!$dataArchive->canDelete()) { |
||
1800 | throw new SS_HTTPResponse_Exception('Not allowed to delete archive', 403); |
||
1801 | } |
||
1802 | |||
1803 | $form = $this->getDeleteForm($this->request, $dataArchive); |
||
1804 | |||
1805 | // View currently only available via ajax |
||
1806 | return $form->forTemplate(); |
||
1807 | } |
||
1808 | |||
1809 | /** |
||
1810 | * @param \SS_HTTPRequest $request |
||
1811 | * @param DNDataArchive|null $dataArchive Only set when method is called manually, otherwise the state is inferred |
||
1812 | * from the request data. |
||
1813 | * @return Form |
||
1814 | */ |
||
1815 | public function getDeleteForm(\SS_HTTPRequest $request, \DNDataArchive $dataArchive = null) { |
||
1816 | $dataArchive = $dataArchive ? $dataArchive : DNDataArchive::get()->byId($request->requestVar('DataArchiveID')); |
||
1817 | |||
1818 | // Performs canView permission check by limiting visible projects |
||
1819 | $project = $this->getCurrentProject(); |
||
1820 | if (!$project) { |
||
1821 | return $this->project404Response(); |
||
1822 | } |
||
1823 | |||
1824 | $snapshotDeleteWarning = '<div class="alert alert-warning">' |
||
1825 | . 'Are you sure you want to permanently delete this snapshot from this archive area?' |
||
1826 | . '</div>'; |
||
1827 | |||
1828 | $form = Form::create( |
||
1829 | $this, |
||
1830 | 'DeleteForm', |
||
1831 | FieldList::create( |
||
1832 | HiddenField::create('DataArchiveID', null, $dataArchive->ID), |
||
1833 | LiteralField::create('Warning', $snapshotDeleteWarning) |
||
1834 | ), |
||
1835 | FieldList::create( |
||
1836 | FormAction::create('doDelete', 'Delete') |
||
1837 | ->addExtraClass('btn') |
||
1838 | ) |
||
1839 | ); |
||
1840 | $form->setFormAction($project->Link() . '/DeleteForm'); |
||
1841 | |||
1842 | return $form; |
||
1843 | } |
||
1844 | |||
1845 | /** |
||
1846 | * @param array $data |
||
1847 | * @param Form $form |
||
1848 | * |
||
1849 | * @return bool|SS_HTTPResponse |
||
1850 | * @throws SS_HTTPResponse_Exception |
||
1851 | */ |
||
1852 | public function doDelete($data, Form $form) { |
||
0 ignored issues
–
show
|
|||
1853 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
1854 | |||
1855 | // Performs canView permission check by limiting visible projects |
||
1856 | $project = $this->getCurrentProject(); |
||
1857 | if (!$project) { |
||
1858 | return $this->project404Response(); |
||
1859 | } |
||
1860 | |||
1861 | $dataArchive = null; |
||
1862 | |||
1863 | if ( |
||
1864 | isset($data['DataArchiveID']) |
||
1865 | && is_numeric($data['DataArchiveID']) |
||
1866 | ) { |
||
1867 | $dataArchive = DNDataArchive::get()->byId($data['DataArchiveID']); |
||
1868 | } |
||
1869 | |||
1870 | if (!$dataArchive) { |
||
1871 | throw new LogicException('Invalid data archive'); |
||
1872 | } |
||
1873 | |||
1874 | if (!$dataArchive->canDelete()) { |
||
1875 | throw new SS_HTTPResponse_Exception('Not allowed to delete archive', 403); |
||
1876 | } |
||
1877 | |||
1878 | $dataArchive->delete(); |
||
1879 | |||
1880 | return $this->redirectBack(); |
||
1881 | } |
||
1882 | |||
1883 | /** |
||
1884 | * View a form to move a specific {@link DataArchive}. |
||
1885 | * |
||
1886 | * @param \SS_HTTPRequest $request |
||
1887 | * |
||
1888 | * @return HTMLText |
||
1889 | * @throws SS_HTTPResponse_Exception |
||
1890 | */ |
||
1891 | View Code Duplication | public function movesnapshot(\SS_HTTPRequest $request) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
1892 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
1893 | |||
1894 | /** @var DNDataArchive $dataArchive */ |
||
1895 | $dataArchive = DNDataArchive::get()->byId($request->param('DataArchiveID')); |
||
1896 | |||
1897 | if (!$dataArchive) { |
||
1898 | throw new SS_HTTPResponse_Exception('Archive not found', 404); |
||
1899 | } |
||
1900 | |||
1901 | // We check for canDownload because that implies access to the data. |
||
1902 | if (!$dataArchive->canDownload()) { |
||
1903 | throw new SS_HTTPResponse_Exception('Not allowed to access archive', 403); |
||
1904 | } |
||
1905 | |||
1906 | $form = $this->getMoveForm($this->request, $dataArchive); |
||
1907 | |||
1908 | // View currently only available via ajax |
||
1909 | return $form->forTemplate(); |
||
0 ignored issues
–
show
The method
forTemplate does only exist in Form , but not in SS_HTTPResponse .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
1910 | } |
||
1911 | |||
1912 | /** |
||
1913 | * Build snapshot move form. |
||
1914 | * |
||
1915 | * @param \SS_HTTPRequest $request |
||
1916 | * @param DNDataArchive|null $dataArchive |
||
1917 | * |
||
1918 | * @return Form|SS_HTTPResponse |
||
1919 | */ |
||
1920 | public function getMoveForm(\SS_HTTPRequest $request, \DNDataArchive $dataArchive = null) { |
||
1921 | $dataArchive = $dataArchive ? $dataArchive : DNDataArchive::get()->byId($request->requestVar('DataArchiveID')); |
||
1922 | |||
1923 | $envs = $dataArchive->validTargetEnvironments(); |
||
1924 | if (!$envs) { |
||
1925 | return $this->environment404Response(); |
||
1926 | } |
||
1927 | |||
1928 | $warningMessage = '<div class="alert alert-warning"><strong>Warning:</strong> This will make the snapshot ' |
||
1929 | . 'available to people with access to the target environment.<br>By pressing "Change ownership" you ' |
||
1930 | . 'confirm that you have considered data confidentiality regulations.</div>'; |
||
1931 | |||
1932 | $form = Form::create( |
||
1933 | $this, |
||
1934 | 'MoveForm', |
||
1935 | FieldList::create( |
||
1936 | HiddenField::create('DataArchiveID', null, $dataArchive->ID), |
||
1937 | LiteralField::create('Warning', $warningMessage), |
||
1938 | DropdownField::create('EnvironmentID', 'Environment', $envs->map()) |
||
1939 | ->setEmptyString('Select an environment') |
||
1940 | ), |
||
1941 | FieldList::create( |
||
1942 | FormAction::create('doMove', 'Change ownership') |
||
1943 | ->addExtraClass('btn') |
||
1944 | ) |
||
1945 | ); |
||
1946 | $form->setFormAction($this->getCurrentProject()->Link() . '/MoveForm'); |
||
1947 | |||
1948 | return $form; |
||
1949 | } |
||
1950 | |||
1951 | /** |
||
1952 | * @param array $data |
||
1953 | * @param Form $form |
||
1954 | * |
||
1955 | * @return bool|SS_HTTPResponse |
||
1956 | * @throws SS_HTTPResponse_Exception |
||
1957 | * @throws ValidationException |
||
1958 | * @throws null |
||
1959 | */ |
||
1960 | public function doMove($data, \Form $form) { |
||
0 ignored issues
–
show
|
|||
1961 | $this->setCurrentActionType(self::ACTION_SNAPSHOT); |
||
1962 | |||
1963 | // Performs canView permission check by limiting visible projects |
||
1964 | $project = $this->getCurrentProject(); |
||
1965 | if (!$project) { |
||
1966 | return $this->project404Response(); |
||
1967 | } |
||
1968 | |||
1969 | /** @var DNDataArchive $dataArchive */ |
||
1970 | $dataArchive = DNDataArchive::get()->byId($data['DataArchiveID']); |
||
1971 | if (!$dataArchive) { |
||
1972 | throw new LogicException('Invalid data archive'); |
||
1973 | } |
||
1974 | |||
1975 | // We check for canDownload because that implies access to the data. |
||
1976 | if (!$dataArchive->canDownload()) { |
||
1977 | throw new SS_HTTPResponse_Exception('Not allowed to access archive', 403); |
||
1978 | } |
||
1979 | |||
1980 | // Validate $data['EnvironmentID'] by checking against $validEnvs. |
||
1981 | $validEnvs = $dataArchive->validTargetEnvironments(); |
||
1982 | $environment = $validEnvs->find('ID', $data['EnvironmentID']); |
||
1983 | if (!$environment) { |
||
1984 | throw new LogicException('Invalid environment'); |
||
1985 | } |
||
1986 | |||
1987 | $dataArchive->EnvironmentID = $environment->ID; |
||
1988 | $dataArchive->write(); |
||
1989 | |||
1990 | return $this->redirectBack(); |
||
1991 | } |
||
1992 | |||
1993 | /** |
||
1994 | * Returns an error message if redis is unavailable |
||
1995 | * |
||
1996 | * @return string |
||
1997 | */ |
||
1998 | public static function RedisUnavailable() { |
||
1999 | try { |
||
2000 | Resque::queues(); |
||
2001 | } catch (Exception $e) { |
||
2002 | return $e->getMessage(); |
||
2003 | } |
||
2004 | return ''; |
||
2005 | } |
||
2006 | |||
2007 | /** |
||
2008 | * Returns the number of connected Redis workers |
||
2009 | * |
||
2010 | * @return int |
||
2011 | */ |
||
2012 | public static function RedisWorkersCount() { |
||
2013 | return count(Resque_Worker::all()); |
||
2014 | } |
||
2015 | |||
2016 | /** |
||
2017 | * @return array |
||
2018 | */ |
||
2019 | public function providePermissions() { |
||
2020 | return [ |
||
2021 | self::DEPLOYNAUT_ADVANCED_DEPLOY_OPTIONS => [ |
||
2022 | 'name' => "Access to advanced deploy options", |
||
2023 | 'category' => "Deploynaut", |
||
2024 | ], |
||
2025 | |||
2026 | // Permissions that are intended to be added to the roles. |
||
2027 | self::ALLOW_PROD_DEPLOYMENT => [ |
||
2028 | 'name' => "Ability to deploy to production environments", |
||
2029 | 'category' => "Deploynaut", |
||
2030 | ], |
||
2031 | self::ALLOW_NON_PROD_DEPLOYMENT => [ |
||
2032 | 'name' => "Ability to deploy to non-production environments", |
||
2033 | 'category' => "Deploynaut", |
||
2034 | ], |
||
2035 | self::ALLOW_PROD_SNAPSHOT => [ |
||
2036 | 'name' => "Ability to make production snapshots", |
||
2037 | 'category' => "Deploynaut", |
||
2038 | ], |
||
2039 | self::ALLOW_NON_PROD_SNAPSHOT => [ |
||
2040 | 'name' => "Ability to make non-production snapshots", |
||
2041 | 'category' => "Deploynaut", |
||
2042 | ], |
||
2043 | self::ALLOW_CREATE_ENVIRONMENT => [ |
||
2044 | 'name' => "Ability to create environments", |
||
2045 | 'category' => "Deploynaut", |
||
2046 | ], |
||
2047 | ]; |
||
2048 | } |
||
2049 | |||
2050 | /** |
||
2051 | * @return DNProject|null |
||
2052 | */ |
||
2053 | public function getCurrentProject() { |
||
2054 | $projectName = trim($this->getRequest()->param('Project')); |
||
2055 | if (!$projectName) { |
||
2056 | return null; |
||
2057 | } |
||
2058 | if (empty(self::$_project_cache[$projectName])) { |
||
2059 | self::$_project_cache[$projectName] = $this->DNProjectList()->filter('Name', $projectName)->First(); |
||
2060 | } |
||
2061 | return self::$_project_cache[$projectName]; |
||
2062 | } |
||
2063 | |||
2064 | /** |
||
2065 | * @param \DNProject|null $project |
||
2066 | * @return \DNEnvironment|null |
||
2067 | */ |
||
2068 | public function getCurrentEnvironment(\DNProject $project = null) { |
||
2069 | if ($this->getRequest()->param('Environment') === null) { |
||
2070 | return null; |
||
2071 | } |
||
2072 | if ($project === null) { |
||
2073 | $project = $this->getCurrentProject(); |
||
2074 | } |
||
2075 | // project can still be null |
||
2076 | if ($project === null) { |
||
2077 | return null; |
||
2078 | } |
||
2079 | return $project->DNEnvironmentList()->filter('Name', $this->getRequest()->param('Environment'))->First(); |
||
2080 | } |
||
2081 | |||
2082 | /** |
||
2083 | * This will return a const that indicates the class of action currently being performed |
||
2084 | * |
||
2085 | * Until DNRoot is de-godded, it does a bunch of different actions all in the same class. |
||
2086 | * So we just have each action handler calll setCurrentActionType to define what sort of |
||
2087 | * action it is. |
||
2088 | * |
||
2089 | * @return string - one of the consts from self::$action_types |
||
2090 | */ |
||
2091 | public function getCurrentActionType() { |
||
2092 | return $this->actionType; |
||
2093 | } |
||
2094 | |||
2095 | /** |
||
2096 | * Sets the current action type |
||
2097 | * |
||
2098 | * @param string $actionType string - one of the consts from self::$action_types |
||
2099 | */ |
||
2100 | public function setCurrentActionType($actionType) { |
||
2101 | $this->actionType = $actionType; |
||
2102 | } |
||
2103 | |||
2104 | /** |
||
2105 | * Helper method to allow templates to know whether they should show the 'Archive List' include or not. |
||
2106 | * The actual permissions are set on a per-environment level, so we need to find out if this $member can upload to |
||
2107 | * or download from *any* {@link DNEnvironment} that (s)he has access to. |
||
2108 | * |
||
2109 | * TODO To be replaced with a method that just returns the list of archives this {@link Member} has access to. |
||
2110 | * |
||
2111 | * @param Member|null $member The {@link Member} to check (or null to check the currently logged in Member) |
||
2112 | * @return boolean|null true if $member has access to upload or download to at least one {@link DNEnvironment}. |
||
2113 | */ |
||
2114 | public function CanViewArchives(\Member $member = null) { |
||
2115 | if ($member === null) { |
||
2116 | $member = Member::currentUser(); |
||
2117 | } |
||
2118 | |||
2119 | if (Permission::checkMember($member, 'ADMIN')) { |
||
2120 | return true; |
||
2121 | } |
||
2122 | |||
2123 | $allProjects = $this->DNProjectList(); |
||
2124 | if (!$allProjects) { |
||
2125 | return false; |
||
2126 | } |
||
2127 | |||
2128 | foreach ($allProjects as $project) { |
||
2129 | if ($project->Environments()) { |
||
2130 | foreach ($project->Environments() as $environment) { |
||
2131 | if ( |
||
2132 | $environment->canRestore($member) || |
||
2133 | $environment->canBackup($member) || |
||
2134 | $environment->canUploadArchive($member) || |
||
2135 | $environment->canDownloadArchive($member) |
||
2136 | ) { |
||
2137 | // We can return early as we only need to know that we can access one environment |
||
2138 | return true; |
||
2139 | } |
||
2140 | } |
||
2141 | } |
||
2142 | } |
||
2143 | } |
||
2144 | |||
2145 | /** |
||
2146 | * Returns a list of attempted environment creations. |
||
2147 | * |
||
2148 | * @return PaginatedList |
||
2149 | */ |
||
2150 | public function CreateEnvironmentList() { |
||
2151 | $project = $this->getCurrentProject(); |
||
2152 | if ($project) { |
||
2153 | $dataList = $project->CreateEnvironments(); |
||
0 ignored issues
–
show
The method
CreateEnvironments() does not exist on DNProject . Did you maybe mean canCreateEnvironments() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
2154 | } else { |
||
2155 | $dataList = new ArrayList(); |
||
2156 | } |
||
2157 | |||
2158 | $this->extend('updateCreateEnvironmentList', $dataList); |
||
2159 | return new PaginatedList($dataList->sort('Created DESC'), $this->request); |
||
0 ignored issues
–
show
$this->request is of type object<SS_HTTPRequest> , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
2160 | } |
||
2161 | |||
2162 | /** |
||
2163 | * Returns a list of all archive files that can be accessed by the currently logged-in {@link Member} |
||
2164 | * |
||
2165 | * @return PaginatedList |
||
2166 | */ |
||
2167 | public function CompleteDataArchives() { |
||
2168 | $project = $this->getCurrentProject(); |
||
2169 | $archives = new ArrayList(); |
||
2170 | |||
2171 | $archiveList = $project->Environments()->relation("DataArchives"); |
||
2172 | if ($archiveList->count() > 0) { |
||
2173 | foreach ($archiveList as $archive) { |
||
2174 | if (!$archive->isPending()) { |
||
2175 | $archives->push($archive); |
||
2176 | } |
||
2177 | } |
||
2178 | } |
||
2179 | return new PaginatedList($archives->sort("Created", "DESC"), $this->request); |
||
0 ignored issues
–
show
$this->request is of type object<SS_HTTPRequest> , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
2180 | } |
||
2181 | |||
2182 | /** |
||
2183 | * @return PaginatedList The list of "pending" data archives which are waiting for a file |
||
2184 | * to be delivered offline by post, and manually uploaded into the system. |
||
2185 | */ |
||
2186 | public function PendingDataArchives() { |
||
2187 | $project = $this->getCurrentProject(); |
||
2188 | $archives = new ArrayList(); |
||
2189 | foreach ($project->DNEnvironmentList() as $env) { |
||
2190 | foreach ($env->DataArchives() as $archive) { |
||
2191 | if ($archive->isPending()) { |
||
2192 | $archives->push($archive); |
||
2193 | } |
||
2194 | } |
||
2195 | } |
||
2196 | return new PaginatedList($archives->sort("Created", "DESC"), $this->request); |
||
0 ignored issues
–
show
$this->request is of type object<SS_HTTPRequest> , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
2197 | } |
||
2198 | |||
2199 | /** |
||
2200 | * @return PaginatedList |
||
2201 | */ |
||
2202 | public function DataTransferLogs() { |
||
2203 | $environments = $this->getCurrentProject()->Environments()->column('ID'); |
||
2204 | $transfers = DNDataTransfer::get() |
||
2205 | ->filter('EnvironmentID', $environments) |
||
2206 | ->filterByCallback( |
||
2207 | function ($record) { |
||
2208 | return |
||
2209 | $record->Environment()->canRestore() || // Ensure member can perform an action on the transfers env |
||
2210 | $record->Environment()->canBackup() || |
||
2211 | $record->Environment()->canUploadArchive() || |
||
2212 | $record->Environment()->canDownloadArchive(); |
||
2213 | }); |
||
2214 | |||
2215 | return new PaginatedList($transfers->sort("Created", "DESC"), $this->request); |
||
0 ignored issues
–
show
$this->request is of type object<SS_HTTPRequest> , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
2216 | } |
||
2217 | |||
2218 | /** |
||
2219 | * @deprecated 2.0.0 - moved to DeployDispatcher |
||
2220 | * |
||
2221 | * @return null|PaginatedList |
||
2222 | */ |
||
2223 | public function DeployHistory() { |
||
2224 | if ($env = $this->getCurrentEnvironment()) { |
||
2225 | $history = $env->DeployHistory(); |
||
2226 | if ($history->count() > 0) { |
||
2227 | $pagination = new PaginatedList($history, $this->getRequest()); |
||
0 ignored issues
–
show
$this->getRequest() is of type object<SS_HTTPRequest> , but the function expects a array .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
2228 | $pagination->setPageLength(4); |
||
2229 | return $pagination; |
||
2230 | } |
||
2231 | } |
||
2232 | return null; |
||
2233 | } |
||
2234 | |||
2235 | /** |
||
2236 | * @param string $status |
||
2237 | * @param string $content |
||
2238 | * |
||
2239 | * @return string |
||
2240 | */ |
||
2241 | public function sendResponse($status, $content) { |
||
2242 | // strip excessive newlines |
||
2243 | $content = preg_replace('/(?:(?:\r\n|\r|\n)\s*){2}/s', "\n", $content); |
||
2244 | |||
2245 | $sendJSON = (strpos($this->getRequest()->getHeader('Accept'), 'application/json') !== false) |
||
2246 | || $this->getRequest()->getExtension() == 'json'; |
||
2247 | |||
2248 | if (!$sendJSON) { |
||
2249 | $this->response->addHeader("Content-type", "text/plain"); |
||
2250 | return $content; |
||
2251 | } |
||
2252 | $this->response->addHeader("Content-type", "application/json"); |
||
2253 | return json_encode([ |
||
2254 | 'status' => $status, |
||
2255 | 'content' => $content, |
||
2256 | ]); |
||
2257 | } |
||
2258 | |||
2259 | /** |
||
2260 | * Get items for the ambient menu that should be accessible from all pages. |
||
2261 | * |
||
2262 | * @return ArrayList |
||
2263 | */ |
||
2264 | public function AmbientMenu() { |
||
2265 | $list = new ArrayList(); |
||
2266 | |||
2267 | if (Member::currentUserID()) { |
||
2268 | $list->push(new ArrayData([ |
||
2269 | 'Classes' => 'logout', |
||
2270 | 'FaIcon' => 'sign-out', |
||
2271 | 'Link' => 'Security/logout', |
||
2272 | 'Title' => 'Log out', |
||
2273 | 'IsCurrent' => false, |
||
2274 | 'IsSection' => false |
||
2275 | ])); |
||
2276 | } |
||
2277 | |||
2278 | $this->extend('updateAmbientMenu', $list); |
||
2279 | return $list; |
||
2280 | } |
||
2281 | |||
2282 | /** |
||
2283 | * Checks whether the user can create a project. |
||
2284 | * |
||
2285 | * @return bool |
||
2286 | */ |
||
2287 | public function canCreateProjects($member = null) { |
||
2288 | if (!$member) { |
||
2289 | $member = Member::currentUser(); |
||
2290 | } |
||
2291 | if (!$member) { |
||
2292 | return false; |
||
2293 | } |
||
2294 | |||
2295 | return singleton('DNProject')->canCreate($member); |
||
2296 | } |
||
2297 | |||
2298 | protected function applyRedeploy(\SS_HTTPRequest $request, &$data) { |
||
2299 | if (!$request->getVar('redeploy')) { |
||
2300 | return; |
||
2301 | } |
||
2302 | |||
2303 | $project = $this->getCurrentProject(); |
||
2304 | if (!$project) { |
||
2305 | return $this->project404Response(); |
||
2306 | } |
||
2307 | |||
2308 | // Performs canView permission check by limiting visible projects |
||
2309 | $env = $this->getCurrentEnvironment($project); |
||
2310 | if (!$env) { |
||
2311 | return $this->environment404Response(); |
||
2312 | } |
||
2313 | |||
2314 | $current = $env->CurrentBuild(); |
||
2315 | if ($current && $current->exists()) { |
||
2316 | $data['preselect_tab'] = 3; |
||
2317 | $data['preselect_sha'] = $current->SHA; |
||
2318 | } else { |
||
2319 | $master = $project->DNBranchList()->byName('master'); |
||
2320 | if ($master) { |
||
2321 | $data['preselect_tab'] = 1; |
||
2322 | $data['preselect_sha'] = $master->SHA(); |
||
0 ignored issues
–
show
|
|||
2323 | } |
||
2324 | } |
||
2325 | } |
||
2326 | |||
2327 | /** |
||
2328 | * @return SS_HTTPResponse |
||
2329 | */ |
||
2330 | protected function project404Response() { |
||
2331 | return new SS_HTTPResponse( |
||
2332 | "Project '" . Convert::raw2xml($this->getRequest()->param('Project')) . "' not found.", |
||
2333 | 404 |
||
2334 | ); |
||
2335 | } |
||
2336 | |||
2337 | /** |
||
2338 | * @return SS_HTTPResponse |
||
2339 | */ |
||
2340 | protected function environment404Response() { |
||
2341 | $envName = Convert::raw2xml($this->getRequest()->param('Environment')); |
||
2342 | return new SS_HTTPResponse("Environment '" . $envName . "' not found.", 404); |
||
2343 | } |
||
2344 | |||
2345 | /** |
||
2346 | * Validate the snapshot mode |
||
2347 | * |
||
2348 | * @param string $mode |
||
2349 | */ |
||
2350 | protected function validateSnapshotMode($mode) { |
||
2351 | if (!in_array($mode, ['all', 'assets', 'db'])) { |
||
2352 | throw new LogicException('Invalid mode'); |
||
2353 | } |
||
2354 | } |
||
2355 | |||
2356 | /** |
||
2357 | * @param string $sectionName |
||
2358 | * @param string $title |
||
2359 | * |
||
2360 | * @return SS_HTTPResponse |
||
2361 | */ |
||
2362 | protected function getCustomisedViewSection($sectionName, $title = '', $data = []) { |
||
2363 | // Performs canView permission check by limiting visible projects |
||
2364 | $project = $this->getCurrentProject(); |
||
2365 | if (!$project) { |
||
2366 | return $this->project404Response(); |
||
2367 | } |
||
2368 | $data[$sectionName] = 1; |
||
2369 | |||
2370 | if ($this !== '') { |
||
2371 | $data['Title'] = $title; |
||
2372 | } |
||
2373 | |||
2374 | return $this->render($data); |
||
2375 | } |
||
2376 | |||
2377 | } |
||
2378 | |||
2379 |
This check marks property names that have not been written in camelCase.
In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes
databaseConnectionString
.