GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (4873)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

include/agiledashboardPlugin.class.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Copyright (c) Enalean, 2012-2015. All Rights Reserved.
4
 *
5
 * This file is a part of Tuleap.
6
 *
7
 * Tuleap is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * Tuleap is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with Tuleap. If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
require_once 'common/plugin/Plugin.class.php';
22
require_once 'autoload.php';
23
require_once 'constants.php';
24
25
/**
26
 * AgileDashboardPlugin
27
 */
28
class AgileDashboardPlugin extends Plugin {
29
30
    const PLUGIN_NAME = 'agiledashboard';
31
32
    private $service;
0 ignored issues
show
The property $service is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
33
34
    /** @var AgileDashboard_SequenceIdManager */
35
    private $sequence_id_manager;
36
37
    /**
38
     * Plugin constructor
39
     */
40
    public function __construct($id) {
41
        parent::__construct($id);
42
        $this->setScope(self::SCOPE_PROJECT);
43
    }
44
45
    public function getHooksAndCallbacks() {
46
        // Do not load the plugin if tracker is not installed & active
47
        if (defined('TRACKER_BASE_URL')) {
48
            require_once dirname(__FILE__) .'/../../tracker/include/autoload.php';
49
            $this->_addHook('cssfile', 'cssfile', false);
50
            $this->_addHook('javascript_file');
51
            $this->_addHook(Event::COMBINED_SCRIPTS, 'combined_scripts', false);
52
            $this->_addHook(TRACKER_EVENT_INCLUDE_CSS_FILE, 'tracker_event_include_css_file', false);
53
            $this->_addHook(TRACKER_EVENT_TRACKERS_DUPLICATED, 'tracker_event_trackers_duplicated', false);
54
            $this->_addHook(TRACKER_EVENT_BUILD_ARTIFACT_FORM_ACTION, 'tracker_event_build_artifact_form_action', false);
55
            $this->_addHook(TRACKER_EVENT_ARTIFACT_ASSOCIATION_EDITED, 'tracker_event_artifact_association_edited', false);
56
            $this->_addHook(TRACKER_EVENT_REDIRECT_AFTER_ARTIFACT_CREATION_OR_UPDATE, 'tracker_event_redirect_after_artifact_creation_or_update', false);
57
            $this->_addHook(TRACKER_EVENT_ARTIFACT_PARENTS_SELECTOR, 'event_artifact_parents_selector', false);
58
            $this->_addHook(TRACKER_EVENT_MANAGE_SEMANTICS, 'tracker_event_manage_semantics', false);
59
            $this->_addHook(TRACKER_EVENT_SEMANTIC_FROM_XML, 'tracker_event_semantic_from_xml');
60
            $this->_addHook(TRACKER_EVENT_SOAP_SEMANTICS, 'tracker_event_soap_semantics');
61
            $this->addHook(TRACKER_EVENT_GET_SEMANTIC_FACTORIES);
62
            $this->addHook('plugin_statistics_service_usage');
63
            $this->addHook(TRACKER_EVENT_REPORT_DISPLAY_ADDITIONAL_CRITERIA);
64
            $this->addHook(TRACKER_EVENT_REPORT_PROCESS_ADDITIONAL_QUERY);
65
            $this->addHook(TRACKER_EVENT_REPORT_SAVE_ADDITIONAL_CRITERIA);
66
            $this->addHook(TRACKER_EVENT_REPORT_LOAD_ADDITIONAL_CRITERIA);
67
            $this->addHook(TRACKER_EVENT_FIELD_AUGMENT_DATA_FOR_REPORT);
68
            $this->addHook(TRACKER_USAGE);
69
            $this->addHook(TRACKER_EVENT_TRACKERS_CANNOT_USE_IN_HIERARCHY);
70
            $this->addHook(Event::SERVICE_ICON);
71
            $this->addHook(Event::SERVICES_ALLOWED_FOR_PROJECT);
72
            $this->_addHook('register_project_creation');
73
74
            $this->_addHook(Event::IMPORT_XML_PROJECT_CARDWALL_DONE);
75
            $this->addHook(Event::REST_RESOURCES);
76
            $this->addHook(Event::REST_RESOURCES_V2);
77
            $this->addHook(Event::REST_PROJECT_ADDITIONAL_INFORMATIONS);
78
            $this->addHook(Event::REST_PROJECT_AGILE_ENDPOINTS);
79
            $this->addHook(Event::REST_GET_PROJECT_PLANNINGS);
80
            $this->addHook(Event::REST_OPTIONS_PROJECT_PLANNINGS);
81
            $this->addHook(Event::REST_PROJECT_RESOURCES);
82
            $this->addHook(Event::REST_GET_PROJECT_MILESTONES);
83
            $this->addHook(Event::REST_OPTIONS_PROJECT_MILESTONES);
84
            $this->addHook(Event::REST_GET_PROJECT_BACKLOG);
85
            $this->addHook(Event::REST_PUT_PROJECT_BACKLOG);
86
            $this->addHook(Event::REST_PATCH_PROJECT_BACKLOG);
87
            $this->addHook(Event::REST_OPTIONS_PROJECT_BACKLOG);
88
            $this->addHook(Event::GET_PROJECTID_FROM_URL);
89
            $this->addHook(ITEM_PRIORITY_CHANGE);
90
        }
91
92
        if (defined('CARDWALL_BASE_URL')) {
93
            $this->addHook(CARDWALL_EVENT_USE_STANDARD_JAVASCRIPT,'cardwall_event_use_standard_javascript');
94
        }
95
96
        return parent::getHooksAndCallbacks();
97
    }
98
99
    /**
100
     * @see Plugin::getDependencies()
101
     */
102
    public function getDependencies() {
103
        return array('tracker', 'cardwall');
104
    }
105
106
    public function getServiceShortname() {
107
        return 'plugin_agiledashboard';
108
    }
109
110
    public function service_icon($params) {
111
        $params['list_of_icon_unicodes'][$this->getServiceShortname()] = '\e80e';
112
    }
113
114
    public function register_project_creation($params) {
115
        $this->getConfigurationManager()->duplicate(
116
            $params['group_id'],
117
            $params['template_id']
118
        );
119
    }
120
121
    /**
122
     * @return AgileDashboard_ConfigurationManager
123
     */
124
    private function getConfigurationManager() {
125
        return new AgileDashboard_ConfigurationManager(
126
            new AgileDashboard_ConfigurationDao()
127
        );
128
    }
129
130
    public function cardwall_event_get_swimline_tracker($params) {
131
        $planning_factory = $this->getPlanningFactory();
132
        if ($planning = $planning_factory->getPlanningByPlanningTracker($params['tracker'])) {
133
            $params['backlog_trackers'] = $planning->getBacklogTrackers();
134
        }
135
    }
136
137
    /**
138
     * @see TRACKER_EVENT_REPORT_DISPLAY_ADDITIONAL_CRITERIA
139
     */
140
    public function tracker_event_report_display_additional_criteria($params) {
141
        $backlog_tracker = $params['tracker'];
142
        if (! $backlog_tracker) {
143
            return;
144
        }
145
146
        $planning_factory = $this->getPlanningFactory();
147
        $user             = $this->getCurrentUser();
148
        $provider         = new AgileDashboard_Milestone_MilestoneReportCriterionProvider(
149
            new AgileDashboard_Milestone_SelectedMilestoneProvider(
150
                $params['additional_criteria'],
151
                $this->getMilestoneFactory(),
152
                $user,
153
                $backlog_tracker->getProject()
154
            ),
155
            new AgileDashboard_Milestone_MilestoneReportCriterionOptionsProvider(
156
                new AgileDashboard_Planning_NearestPlanningTrackerProvider($planning_factory),
157
                new AgileDashboard_Milestone_MilestoneDao(),
158
                Tracker_HierarchyFactory::instance(),
159
                $planning_factory
160
            )
161
        );
162
        $additional_criterion = $provider->getCriterion($backlog_tracker, $user);
163
164
        if (! $additional_criterion) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $additional_criterion of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
165
            return;
166
        }
167
168
        $params['array_of_html_criteria'][] = $additional_criterion;
169
    }
170
171
    /**
172
     * @see TRACKER_EVENT_REPORT_PROCESS_ADDITIONAL_QUERY
173
     */
174
    public function tracker_event_report_process_additional_query($params) {
175
        $backlog_tracker = $params['tracker'];
176
177
        $user    = $params['user'];
178
        $project = $backlog_tracker->getProject();
179
180
        $milestone_provider = new AgileDashboard_Milestone_SelectedMilestoneProvider($params['additional_criteria'], $this->getMilestoneFactory(), $user, $project);
181
        $milestone          = $milestone_provider->getMilestone();
182
183
        if ($milestone) {
184
            $provider = new AgileDashboard_BacklogItem_SubBacklogItemProvider(new Tracker_ArtifactDao(), $this->getBacklogStrategyFactory(), $this->getBacklogItemCollectionFactory());
185
            $params['result'][]         = $provider->getMatchingIds($milestone, $backlog_tracker, $user);
186
            $params['search_performed'] = true;
187
        }
188
    }
189
190
    /**
191
     * @see TRACKER_EVENT_REPORT_SAVE_ADDITIONAL_CRITERIA
192
     */
193
    public function tracker_event_report_save_additional_criteria($params) {
194
        $dao     = new MilestoneReportCriterionDao();
195
        $project = $params['report']->getTracker()->getProject();
196
        $user    = $this->getCurrentUser();
197
198
        $milestone_provider = new AgileDashboard_Milestone_SelectedMilestoneProvider($params['additional_criteria'], $this->getMilestoneFactory(), $user, $project);
199
200
        if ($milestone_provider->getMilestone()) {
201
            $dao->save($params['report']->getId(), $milestone_provider->getMilestoneId());
202
        } else {
203
            $dao->delete($params['report']->getId());
204
        }
205
    }
206
207
    /**
208
     * @see TRACKER_EVENT_REPORT_LOAD_ADDITIONAL_CRITERIA
209
     */
210
    public function tracker_event_report_load_additional_criteria($params) {
211
        $dao        = new MilestoneReportCriterionDao();
212
        $report_id  = $params['report']->getId();
213
        $field_name = AgileDashboard_Milestone_MilestoneReportCriterionProvider::FIELD_NAME;
214
215
        $row = $dao->searchByReportId($report_id)->getRow();
216
        if ($row){
217
            $params['additional_criteria_values'][$field_name]['value'] = $row['milestone_id'];
218
        }
219
    }
220
221
    public function event_artifact_parents_selector($params) {
222
        $artifact_parents_selector = new Planning_ArtifactParentsSelector(
223
            $this->getArtifactFactory(),
224
            PlanningFactory::build(),
225
            $this->getMilestoneFactory(),
226
            $this->getHierarchyFactory()
227
        );
228
        $event_listener = new Planning_ArtifactParentsSelectorEventListener($this->getArtifactFactory(), $artifact_parents_selector, HTTPRequest::instance());
229
        $event_listener->process($params);
230
    }
231
232
    public function tracker_event_include_css_file($params) {
233
        $params['include_tracker_css_file'] = true;
234
    }
235
236
    public function tracker_event_trackers_duplicated($params) {
237
        PlanningFactory::build()->duplicatePlannings(
238
            $params['group_id'],
239
            $params['tracker_mapping'],
240
            $params['ugroups_mapping']
241
        );
242
243
        $this->getKanbanManager()->duplicateKanbans($params['tracker_mapping'], $params['field_mapping']);
244
    }
245
246
    public function tracker_event_redirect_after_artifact_creation_or_update($params) {
247
        $params_extractor        = new AgileDashboard_PaneRedirectionExtractor();
248
        $artifact_linker         = new Planning_ArtifactLinker($this->getArtifactFactory(), PlanningFactory::build());
249
        $last_milestone_artifact = $artifact_linker->linkBacklogWithPlanningItems($params['request'], $params['artifact']);
250
        $requested_planning      = $params_extractor->extractParametersFromRequest($params['request']);
251
252
        if ($requested_planning) {
253
            $this->redirectOrAppend($params['request'], $params['artifact'], $params['redirect'], $requested_planning, $last_milestone_artifact);
254
        }
255
    }
256
257
    public function tracker_usage($params) {
258
        $tracker    = $params['tracker'];
259
        $tracker_id = $tracker->getId();
260
261
        $is_used_in_planning = PlanningFactory::build()->isTrackerIdUsedInAPlanning($tracker_id);
262
        $is_used_in_backlog  = PlanningFactory::build()->isTrackerUsedInBacklog($tracker_id);
263
        $is_used_in_kanban   = $this->getKanbanManager()->doesKanbanExistForTracker($tracker);
264
265
        if ($is_used_in_planning || $is_used_in_backlog || $is_used_in_kanban) {
266
            $result['can_be_deleted'] = false;
267
            $result['message']        = 'Agile Dashboard';
268
            $params['result']         = $result;
269
        }
270
271
    }
272
273
    private function redirectOrAppend(Codendi_Request $request, Tracker_Artifact $artifact, Tracker_Artifact_Redirect $redirect, $requested_planning, Tracker_Artifact $last_milestone_artifact = null) {
274
        $planning = PlanningFactory::build()->getPlanning($requested_planning['planning_id']);
275
276
        if ($planning && ! $redirect->stayInTracker()) {
277
            $this->redirectToPlanning($artifact, $requested_planning, $planning, $redirect);
278
        } elseif (! $redirect->stayInTracker()) {
279
            $this->redirectToTopPlanning($artifact, $requested_planning, $redirect);
280
        } else {
281
             $this->setQueryParametersFromRequest($request, $redirect);
282
             // Pass the right parameters so parent can be created in the right milestone (see updateBacklogs)
283
             if ($planning && $last_milestone_artifact && $redirect->mode == Tracker_Artifact_Redirect::STATE_CREATE_PARENT) {
284
                 $redirect->query_parameters['child_milestone'] = $last_milestone_artifact->getId();
285
             }
286
        }
287
    }
288
289
    private function redirectToPlanning(Tracker_Artifact $artifact, $requested_planning, Planning $planning, Tracker_Artifact_Redirect $redirect) {
290
        $redirect_to_artifact = $requested_planning[AgileDashboard_PaneRedirectionExtractor::ARTIFACT_ID];
291
        if ($redirect_to_artifact == -1) {
292
            $redirect_to_artifact = $artifact->getId();
293
        }
294
        $redirect->base_url = '/plugins/agiledashboard/';
295
        $redirect->query_parameters = array(
296
            'group_id'    => $planning->getGroupId(),
297
            'planning_id' => $planning->getId(),
298
            'action'      => 'show',
299
            'aid'         => $redirect_to_artifact,
300
            'pane'        => $requested_planning[AgileDashboard_PaneRedirectionExtractor::PANE],
301
        );
302
    }
303
304
    private function redirectToTopPlanning(Tracker_Artifact $artifact, $requested_planning, Tracker_Artifact_Redirect $redirect) {
305
        $redirect->base_url = '/plugins/agiledashboard/';
306
        $group_id = null;
307
308
        if ($artifact->getTracker() &&  $artifact->getTracker()->getProject()) {
309
            $group_id = $artifact->getTracker()->getProject()->getID();
310
        }
311
312
        $redirect->query_parameters = array(
313
            'group_id'    => $group_id,
314
            'action'      => 'show-top',
315
            'pane'        => $requested_planning['pane'],
316
        );
317
    }
318
319
    public function tracker_event_build_artifact_form_action($params) {
320
        $this->setQueryParametersFromRequest($params['request'], $params['redirect']);
321
        if ($params['request']->exist('child_milestone')) {
322
            $params['redirect']->query_parameters['child_milestone'] = $params['request']->getValidated('child_milestone', 'uint', 0);
323
        }
324
    }
325
326
    private function setQueryParametersFromRequest(Codendi_Request $request, Tracker_Artifact_Redirect $redirect) {
327
        $params_extractor   = new AgileDashboard_PaneRedirectionExtractor();
328
        $requested_planning = $params_extractor->extractParametersFromRequest($request);
329
        if ($requested_planning) {
330
            $key   = 'planning['. $requested_planning[AgileDashboard_PaneRedirectionExtractor::PANE] .']['. $requested_planning[AgileDashboard_PaneRedirectionExtractor::PLANNING_ID] .']';
331
            $value = $requested_planning[AgileDashboard_PaneRedirectionExtractor::ARTIFACT_ID];
332
            $redirect->query_parameters[$key] = $value;
333
        }
334
    }
335
336
    /**
337
     * @return AgileDashboardPluginInfo
338
     */
339
    public function getPluginInfo() {
340
        if (!$this->pluginInfo) {
341
            $this->pluginInfo = new AgileDashboardPluginInfo($this);
342
        }
343
        return $this->pluginInfo;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->pluginInfo; of type AgileDashboardPluginInfo|AdminDelegationPluginInfo adds the type AdminDelegationPluginInfo to the return on line 343 which is incompatible with the return type documented by AgileDashboardPlugin::getPluginInfo of type AgileDashboardPluginInfo.
Loading history...
344
    }
345
346
    public function cssfile($params) {
347
        if ($this->isAnAgiledashboardRequest()) {
348
            echo '<link rel="stylesheet" type="text/css" href="'.$this->getThemePath().'/css/style.css" />';
349
350
            if ($this->isPlanningV2URL()) {
351
                echo '<link rel="stylesheet" type="text/css" href="'.$this->getPluginPath().'/js/planning-v2/bin/assets/planning-v2.css" />';
352
            }
353
        }
354
    }
355
356
    public function javascript_file() {
357
        if ($this->isAnAgiledashboardRequest()) {
358
            if ($this->isPlanningV2URL()) {
359
                echo '<script type="text/javascript" src="' . $this->getPluginPath() . '/js/planning-v2/bin/assets/planning-v2.js"></script>';
360
            } elseif ($this->isKanbanURL()) {
361
                echo '<script type="text/javascript" src="js/resize-content.js"></script>'."\n";
362
            }
363
        }
364
    }
365
366
    private function isAnAgiledashboardRequest() {
367
        return strpos($_SERVER['REQUEST_URI'], $this->getPluginPath()) === 0;
368
    }
369
370
    private function isKanbanURL() {
371
        $request = HTTPRequest::instance();
372
373
        return $request->get('action') === 'showKanban';
374
    }
375
376
    private function isPlanningV2URL() {
377
        $request = HTTPRequest::instance();
378
        $pane_info_identifier = new AgileDashboard_PaneInfoIdentifier();
379
380
        return $pane_info_identifier->isPaneAPlanningV2($request->get('pane'));
381
    }
382
383
    public function combined_scripts($params) {
384
        $params['scripts'] = array_merge(
385
            $params['scripts'],
386
            array(
387
                $this->getPluginPath().'/js/load-more-milestones.js',
388
                $this->getPluginPath().'/js/display-angular-feedback.js',
389
                $this->getPluginPath().'/js/MilestoneContent.js',
390
                $this->getPluginPath().'/js/planning.js',
391
                $this->getPluginPath().'/js/OuterGlow.js',
392
                $this->getPluginPath().'/js/expand-collapse.js',
393
                $this->getPluginPath().'/js/planning-view.js',
394
                $this->getPluginPath().'/js/ContentFilter.js',
395
                $this->getPluginPath().'/js/home.js',
396
            )
397
        );
398
    }
399
400
    public function process(Codendi_Request $request) {
401
        $builder = new AgileDashboardRouterBuilder();
402
        $router  = $builder->build($request);
403
404
        $router->route($request);
405
    }
406
407
    /**
408
     * Builds a new PlanningFactory instance.
409
     *
410
     * @return PlanningFactory
411
     */
412
    protected function getPlanningFactory() {
413
        return PlanningFactory::build();
414
    }
415
416
    /**
417
     * Builds a new Planning_MilestoneFactory instance.
418
     * @return Planning_MilestoneFactory
419
     */
420
    protected function getMilestoneFactory() {
421
        return new Planning_MilestoneFactory(
422
            $this->getPlanningFactory(),
423
            $this->getArtifactFactory(),
424
            Tracker_FormElementFactory::instance(),
425
            $this->getTrackerFactory(),
426
            $this->getStatusCounter(),
427
            new PlanningPermissionsManager(),
428
            new AgileDashboard_Milestone_MilestoneDao()
429
        );
430
    }
431
432
    private function getArtifactFactory() {
433
        return Tracker_ArtifactFactory::instance();
434
    }
435
436
    private function getHierarchyFactory() {
437
        return Tracker_HierarchyFactory::instance();
438
    }
439
440
    private function getBacklogStrategyFactory() {
441
        return new AgileDashboard_Milestone_Backlog_BacklogStrategyFactory(
442
            new AgileDashboard_BacklogItemDao(),
443
            $this->getArtifactFactory(),
444
            PlanningFactory::build()
445
        );
446
    }
447
448
    public function tracker_event_artifact_association_edited($params) {
449
        if ($params['request']->isAjax()) {
450
451
            $milestone_factory = $this->getMilestoneFactory();
452
            $milestone = $milestone_factory->getBareMilestoneByArtifact($params['user'], $params['artifact']);
453
454
            $milestone_with_contextual_info = $milestone_factory->updateMilestoneContextualInfo($params['user'], $milestone);
0 ignored issues
show
It seems like $milestone defined by $milestone_factory->getB...], $params['artifact']) on line 452 can be null; however, Planning_MilestoneFactor...lestoneContextualInfo() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
455
456
            $capacity         = $milestone_with_contextual_info->getCapacity();
457
            $remaining_effort = $milestone_with_contextual_info->getRemainingEffort();
458
459
            header('Content-type: application/json');
460
            echo json_encode(array(
461
                'remaining_effort' => $remaining_effort,
462
                'is_over_capacity' => $capacity !== null && $remaining_effort !== null && $capacity < $remaining_effort,
463
            ));
464
        }
465
    }
466
467
    /**
468
     * @see Event::TRACKER_EVENT_MANAGE_SEMANTICS
469
     */
470
    public function tracker_event_manage_semantics($parameters) {
471
        $tracker   = $parameters['tracker'];
472
        /* @var $semantics Tracker_SemanticCollection */
473
        $semantics = $parameters['semantics'];
474
475
        $effort_semantic = AgileDashBoard_Semantic_InitialEffort::load($tracker);
476
        $semantics->add($effort_semantic->getShortName(), $effort_semantic);
477
    }
478
479
    /**
480
     * @see Event::TRACKER_EVENT_SEMANTIC_FROM_XML
481
     */
482
    public function tracker_event_semantic_from_xml(&$parameters) {
483
        $tracker    = $parameters['tracker'];
484
        $xml        = $parameters['xml'];
485
        $xmlMapping = $parameters['xml_mapping'];
486
        $type       = $parameters['type'];
487
488
        if ($type == AgileDashBoard_Semantic_InitialEffort::NAME) {
489
            $parameters['semantic'] = $this->getSemanticInitialEffortFactory()->getInstanceFromXML($xml, $xmlMapping, $tracker);
490
        }
491
    }
492
493
    /**
494
     * @see TRACKER_EVENT_GET_SEMANTIC_FACTORIES
495
     */
496
    public function tracker_event_get_semantic_factories($params) {
497
        $params['factories'][] = $this->getSemanticInitialEffortFactory();
498
    }
499
500
    protected function getSemanticInitialEffortFactory() {
501
        return AgileDashboard_Semantic_InitialEffortFactory::instance();
502
    }
503
504
    /**
505
     * Augment $params['semantics'] with names of AgileDashboard semantics
506
     *
507
     * @see TRACKER_EVENT_SOAP_SEMANTICS
508
     */
509
    public function tracker_event_soap_semantics(&$params) {
510
        $params['semantics'][] = AgileDashBoard_Semantic_InitialEffort::NAME;
511
    }
512
513
    /**
514
     *
515
     * @param array $param
0 ignored issues
show
There is no parameter named $param. Did you maybe mean $params?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
516
     *  Expected key/ values:
517
     *      project_id  int             The ID of the project for the import
518
     *      xml_content SimpleXmlObject A string of valid xml
519
     *      mapping     array           An array of mappings between xml tracker IDs and their true IDs
520
     *
521
     */
522
    public function import_xml_project_cardwall_done($params) {
523
        $request = new HTTPRequest($params);
524
        $request->set('action', 'import');
525
        $request->set('xml_content', $params['xml_content']);
526
        $request->set('mapping', $params['mapping']);
527
        $request->set('project_id', $params['project_id']);
528
529
        $this->process($request);
530
    }
531
532
    public function plugin_statistics_service_usage($params) {
533
        $dao                  = new AgileDashboard_Dao();
534
        $statistic_aggregator = new AgileDashboardStatisticsAggregator();
535
        $params['csv_exporter']->buildDatas($dao->getProjectsWithADActivated(), "Agile Dashboard activated");
536
        foreach ($statistic_aggregator->getStatisticsLabels() as $statistic_key => $statistic_name) {
537
            $statistic_data = $statistic_aggregator->getStatistics(
538
                $statistic_key,
539
                $params['start_date'],
540
                $params['end_date']
541
            );
542
            $params['csv_exporter']->buildDatas($statistic_data, $statistic_name);
543
        }
544
    }
545
546
    /**
547
     * @see REST_PROJECT_ADDITIONAL_INFORMATIONS
548
     */
549
    public function rest_project_additional_informations($params) {
550
        $planning_representation_class = '\\Tuleap\\AgileDashboard\\REST\\v1\\PlanningRepresentation';
551
552
        $root_planning = $this->getPlanningFactory()->getRootPlanning($this->getCurrentUser(), $params['project']->getGroupId());
553
        if (! $root_planning) {
554
            return;
555
        }
556
557
        $planning_representation = new $planning_representation_class();
558
        $planning_representation->build($root_planning);
559
560
        $params['informations'][$this->getName()]['root_planning'] = $planning_representation;
561
    }
562
563
    /**
564
     * @see REST_RESOURCES
565
     */
566
    public function rest_resources($params) {
567
        $injector = new AgileDashboard_REST_ResourcesInjector();
568
        $injector->populate($params['restler']);
569
570
        EventManager::instance()->processEvent(
571
            AGILEDASHBOARD_EVENT_REST_RESOURCES,
572
            $params
573
        );
574
    }
575
576
    /**
577
     * @see REST_RESOURCES_V2
578
     */
579
    public function rest_resources_v2($params) {
580
        $injector = new AgileDashboard_REST_v2_ResourcesInjector();
581
        $injector->populate($params['restler']);
582
    }
583
584
    /**
585
     * @see REST_GET_PROJECT_PLANNINGS
586
     */
587
    public function rest_get_project_plannings($params) {
588
        $user              = $this->getCurrentUser();
589
        $planning_resource = $this->buildRightVersionOfProjectPlanningsResource($params['version']);
590
591
        $params['result'] = $planning_resource->get(
592
            $user,
593
            $params['project'],
594
            $params['limit'],
595
            $params['offset']
596
        );
597
    }
598
599
    /**
600
     * @see REST_OPTIONS_PROJECT_PLANNINGS
601
     */
602
    public function rest_options_project_plannings($params) {
603
        $user              = $this->getCurrentUser();
604
        $planning_resource = $this->buildRightVersionOfProjectPlanningsResource($params['version']);
605
606
        $params['result'] = $planning_resource->options(
607
            $user,
608
            $params['project'],
609
            $params['limit'],
610
            $params['offset']
611
        );
612
    }
613
614
    private function buildRightVersionOfProjectPlanningsResource($version) {
615
        $class_with_right_namespace = '\\Tuleap\\AgileDashboard\\REST\\'.$version.'\\ProjectPlanningsResource';
616
        return new $class_with_right_namespace;
617
    }
618
619
    /**
620
     * @see Event::REST_PROJECT_RESOURCES
621
     */
622
    public function rest_project_resources(array $params) {
623
        $injector = new AgileDashboard_REST_ResourcesInjector();
624
        $injector->declareProjectPlanningResource($params['resources'], $params['project']);
625
    }
626
627
    /**
628
     * @see REST_GET_PROJECT_MILESTONES
629
     */
630
    public function rest_get_project_milestones($params) {
631
        $user               = $this->getCurrentUser();
632
        $milestone_resource = $this->buildRightVersionOfProjectMilestonesResource($params['version']);
633
634
        $params['result'] = $milestone_resource->get(
635
            $user,
636
            $params['project'],
637
            $params['representation_type'],
638
            $params['query'],
639
            $params['limit'],
640
            $params['offset'],
641
            $params['order']
642
        );
643
    }
644
645
    /**
646
     * @see REST_OPTIONS_PROJECT_MILESTONES
647
     */
648
    public function rest_options_project_milestones($params) {
649
        $user               = $this->getCurrentUser();
650
        $milestone_resource = $this->buildRightVersionOfProjectMilestonesResource($params['version']);
651
652
        $params['result'] = $milestone_resource->options(
653
            $user,
654
            $params['project'],
655
            $params['limit'],
656
            $params['offset']
657
        );
658
    }
659
660
    private function buildRightVersionOfProjectMilestonesResource($version) {
661
        $class_with_right_namespace = '\\Tuleap\\AgileDashboard\\REST\\'.$version.'\\ProjectMilestonesResource';
662
        return new $class_with_right_namespace;
663
    }
664
665
    /**
666
     * @see REST_GET_PROJECT_BACKLOG
667
     */
668
    public function rest_get_project_backlog($params) {
669
        $user                     = $this->getCurrentUser();
670
        $project_backlog_resource = $this->buildRightVersionOfProjectBacklogResource($params['version']);
671
672
        $params['result'] = $project_backlog_resource->get(
673
            $user,
674
            $params['project'],
675
            $params['limit'],
676
            $params['offset']
677
        );
678
    }
679
680
    /**
681
     * @see REST_OPTIONS_PROJECT_BACKLOG
682
     */
683
    public function rest_options_project_backlog($params) {
684
        $user                     = $this->getCurrentUser();
685
        $project_backlog_resource = $this->buildRightVersionOfProjectBacklogResource($params['version']);
686
687
        $params['result'] = $project_backlog_resource->options(
688
            $user,
689
            $params['project'],
690
            $params['limit'],
691
            $params['offset']
692
        );
693
    }
694
695
    /**
696
     * @see REST_PUT_PROJECT_BACKLOG
697
     */
698
    public function rest_put_project_backlog($params) {
699
        $user                     = $this->getCurrentUser();
700
        $project_backlog_resource = $this->buildRightVersionOfProjectBacklogResource($params['version']);
701
702
        $params['result'] = $project_backlog_resource->put(
703
            $user,
704
            $params['project'],
705
            $params['ids']
706
        );
707
    }
708
709
    /**
710
     * @see REST_PATCH_PROJECT_BACKLOG
711
     */
712
    public function rest_patch_project_backlog($params) {
713
        $user                     = UserManager::instance()->getCurrentUser();
714
        $project_backlog_resource = $this->buildRightVersionOfProjectBacklogResource($params['version']);
715
716
        $params['result'] = $project_backlog_resource->patch(
717
            $user,
718
            $params['project'],
719
            $params['order'],
720
            $params['add']
721
        );
722
    }
723
724
    /**
725
    * @see ITEM_PRIORITY_CHANGE
726
    */
727
    public function item_priority_change($params) {
728
        $planning_id = $this->getPlanningIdFromParameters($params);
729
730
        $params['user_is_authorized'] = $this->getPlanningPermissionsManager()->userHasPermissionOnPlanning(
731
            $planning_id,
732
            $params['group_id'],
733
            $params['user'],
734
            PlanningPermissionsManager::PERM_PRIORITY_CHANGE
735
        );
736
    }
737
738
    private function getPlanningIdFromParameters($params) {
739
        if ($params['milestone_id'] == 0) {
740
            $planning = $this->getPlanningFactory()->getRootPlanning(
741
                $params['user'],
742
                $params['group_id']
743
            );
744
745
            return $planning->getId();
746
        }
747
748
        $artifact    = $this->getArtifactFactory()->getArtifactById($params['milestone_id']);
749
        $milestone   = $this->getMilestoneFactory()->getMilestoneFromArtifact($artifact);
750
751
        return $milestone->getPlanningId();
752
753
    }
754
755
    private function buildRightVersionOfProjectBacklogResource($version) {
756
        $class_with_right_namespace = '\\Tuleap\\AgileDashboard\\REST\\'.$version.'\\ProjectBacklogResource';
757
        return new $class_with_right_namespace;
758
    }
759
760
    private function getStatusCounter() {
761
        return new AgileDashboard_Milestone_MilestoneStatusCounter(
762
            new AgileDashboard_BacklogItemDao(),
763
            new Tracker_ArtifactDao(),
764
            $this->getArtifactFactory()
765
        );
766
    }
767
768
    /** @see Event::GET_PROJECTID_FROM_URL */
769
    public function get_projectid_from_url($params) {
770
        if (strpos($params['url'],'/plugins/agiledashboard/') === 0) {
771
            $params['project_id'] = $params['request']->get('group_id');
772
        }
773
    }
774
775
    /**
776
     * @see TRACKER_EVENT_FIELD_AUGMENT_DATA_FOR_REPORT
777
     */
778
    public function tracker_event_field_augment_data_for_report($params) {
779
        if (! $this->isFieldPriority($params['field'])) {
780
            return;
781
        }
782
783
        $params['result'] = $this->getFieldPriorityAugmenter()->getAugmentedDataForFieldPriority(
784
            $this->getCurrentUser(),
785
            $params['field']->getTracker()->getProject(),
786
            $params['additional_criteria'],
787
            $params['artifact_id']
788
        );
789
    }
790
791
    private function getFieldPriorityAugmenter() {
792
        return new AgileDashboard_FieldPriorityAugmenter(
793
            $this->getSequenceIdManager(),
794
            $this->getMilestoneFactory()
795
        );
796
    }
797
798
    private function isFieldPriority(Tracker_FormElement_Field $field) {
799
        return $field instanceof Tracker_FormElement_Field_Priority;
800
    }
801
802
    private function getSequenceIdManager() {
803
        if (! $this->sequence_id_manager) {
804
            $this->sequence_id_manager = new AgileDashboard_SequenceIdManager(
805
                    $this->getBacklogStrategyFactory(),
806
                    $this->getBacklogItemCollectionFactory()
807
            );
808
        }
809
810
        return $this->sequence_id_manager;
811
    }
812
813
    private function getBacklogItemCollectionFactory() {
814
        return new AgileDashboard_Milestone_Backlog_BacklogItemCollectionFactory(
815
            new AgileDashboard_BacklogItemDao(),
816
            $this->getArtifactFactory(),
817
            Tracker_FormElementFactory::instance(),
818
            $this->getMilestoneFactory(),
819
            $this->getPlanningFactory(),
820
            new AgileDashboard_Milestone_Backlog_BacklogItemBuilder()
821
        );
822
    }
823
824
    public function cardwall_event_use_standard_javascript($params) {
825
        $request = HTTPRequest::instance();
826
        $pane_info_identifier = new AgileDashboard_PaneInfoIdentifier();
827
        if ($pane_info_identifier->isPaneAPlanningV2($request->get('pane')) || $this->isKanbanURL()) {
828
            $params['use_standard'] = false;
829
        }
830
    }
831
832
833
    public function rest_project_agile_endpoints($params) {
834
        $params['available'] = true;
835
    }
836
837
    public function tracker_event_trackers_cannot_use_in_hierarchy($params) {
838
        $params['result'] = array_merge(
839
            $params['result'],
840
            $this->getHierarchyChecker()->getDeniedTrackersForATrackerHierarchy($params['tracker'], $params['user'])
841
        );
842
    }
843
844
    /**
845
     * @return TrackerFactory
846
     */
847
    private function getTrackerFactory() {
848
        return TrackerFactory::instance();
849
    }
850
851
    /**
852
     * @return AgileDashboard_KanbanManager
853
     */
854
    private function getKanbanManager() {
855
        return new AgileDashboard_KanbanManager(
856
            new AgileDashboard_KanbanDao(),
857
            $this->getTrackerFactory(),
858
            $this->getHierarchyChecker()
859
        );
860
    }
861
862
    private function getCurrentUser() {
863
        return UserManager::instance()->getCurrentUser();
864
    }
865
866
    private function getPlanningPermissionsManager() {
867
        return new PlanningPermissionsManager();
868
    }
869
870
    /**
871
     * @return AgileDashboard_HierarchyChecker
872
     */
873
    private function getHierarchyChecker() {
874
        return new AgileDashboard_HierarchyChecker(
875
            $this->getPlanningFactory(),
876
            $this->getKanbanFactory(),
877
            $this->getTrackerFactory()
878
        );
879
    }
880
881
    /**
882
     * @return AgileDashboard_KanbanFactory
883
     */
884
    private function getKanbanFactory() {
885
        return new AgileDashboard_KanbanFactory(
886
            TrackerFactory::instance(),
887
            new AgileDashboard_KanbanDao()
888
889
        );
890
    }
891
}
892