variant_action()   F
last analyzed

Complexity

Conditions 20
Paths > 20000

Size

Total Lines 101
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 67
nc 27652
nop 1
dl 0
loc 101
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// This file is part of BOINC.
3
// https://boinc.berkeley.edu
4
// Copyright (C) 2024 University of California
5
//
6
// BOINC is free software; you can redistribute it and/or modify it
7
// under the terms of the GNU Lesser General Public License
8
// as published by the Free Software Foundation,
9
// either version 3 of the License, or (at your option) any later version.
10
//
11
// BOINC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
// See the GNU Lesser General Public License for more details.
15
//
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18
19
// interface for:
20
//      - viewing details of BUDA science apps and variants
21
//      - managing these if user has permission
22
//
23
// in the following, 'app' means BUDA science app
24
// and 'variant' means a variant of one of these (e.g. CPU, GPU)
25
26
require_once('../inc/util.inc');
27
require_once('../inc/sandbox.inc');
28
require_once('../inc/keywords.inc');
29
require_once('../inc/submit_util.inc');
30
require_once('../inc/buda.inc');
31
32
display_errors();
33
34
$buda_root = "../../buda_apps";
35
36
// scan BUDA apps and variants, and write a file 'buda_plan_classes'
37
// in the project dir with list of plan classes
38
//
39
function write_plan_class_file() {
40
    $pcs = [];
41
    global $buda_root;
42
    $apps = get_buda_apps();
43
    foreach ($apps as $app) {
44
        $vars = get_buda_variants($app);
45
        $pcs = array_merge($pcs, $vars);
46
    }
47
    $pcs = array_unique($pcs);
48
    file_put_contents(
49
        "../../buda_plan_classes",
50
        implode("\n", $pcs)."\n"
51
    );
52
}
53
54
// show list of BUDA apps and variants,
55
// w/ buttons for adding and deleting
56
//
57
function app_list($notice=null) {
58
    global $buda_root;
59
    if (!is_dir($buda_root)) {
60
        mkdir($buda_root);
61
    }
62
    page_head('Manage BUDA apps');
63
    if ($notice) {
64
        echo "$notice <p>\n";
65
    }
66
    text_start();
67
    echo "
68
        <p>BUDA lets you submit Docker jobs using a web interface.
69
        <a href=https://github.com/BOINC/boinc/wiki/BUDA-overview>Learn more</a>.
70
        <p>
71
        <h3>BUDA science apps</h3>
72
    ";
73
74
    $apps = get_buda_apps();
75
    foreach ($apps as $app) {
76
        show_app($app);
77
    }
78
    echo '<hr>';
79
    show_button_small('buda.php?action=app_form', 'Add science app');
80
    text_end();
81
    page_tail();
82
}
83
84
function show_app($dir) {
85
    global $buda_root;
86
    $desc = null;
87
    $desc_path = "$buda_root/$dir/desc.json";
88
    $desc = json_decode(file_get_contents($desc_path));
89
    echo '<hr>';
90
    echo sprintf('<h3>%s</h3>', $desc->long_name);
91
    echo sprintf('<a href=buda.php?action=app_details&name=%s>Details</a>',
92
        $desc->name
93
    );
94
    $vars = get_buda_variants($dir);
95
    if ($vars) {
96
        echo "<p>Variants:<ul>";
97
        foreach ($vars as $var) {
98
            echo sprintf(
99
                '<li><a href=buda.php?action=variant_view&app=%s&variant=%s>%s</a>',
100
                $dir, $var, $var
101
            );
102
        }
103
        echo '</ul>';
104
    } else {
105
        echo '<p>No variants';
106
    }
107
    echo "<p>";
108
}
109
110
function file_row($app, $variant, $dir, $f) {
111
    [$md5, $size] = parse_info_file("$dir/.md5/$f");
112
    table_row(
113
        "<a href=buda.php?action=view_file&app=$app&variant=$variant&fname=$f>$f</a>",
114
        $size,
115
        $md5
116
    );
117
}
118
119
function variant_view() {
120
    global $buda_root, $manage_access;
121
    $app = get_str('app');
122
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
123
    $variant = get_str('variant');
124
    if (!is_valid_filename($variant)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
125
    page_head("BUDA: variant '$variant' of science app '$app'");
126
    $dir = "$buda_root/$app/$variant";
127
    $desc = json_decode(file_get_contents("$dir/variant.json"));
128
    echo "<h3>Files</h3>";
129
    start_table();
130
    table_header('Dockerfile', 'size', 'md5');
131
    file_row($app, $variant, $dir, $desc->dockerfile);
132
    table_header('App files', '', '');
133
    foreach ($desc->app_files as $f) {
134
        file_row($app, $variant, $dir, $f);
135
    }
136
    table_header('Auto-generated files', '', '');
137
    file_row($app, $variant, $dir, 'template_in');
138
    file_row($app, $variant, $dir, 'template_out');
139
    file_row($app, $variant, $dir, 'variant.json');
140
    end_table();
141
    echo '<hr>';
142
143
    start_table();
144
    row2(
145
        'Input filenames:',
146
        implode(',', $desc->input_file_names)
147
    );
148
    row2(
149
        'Output filenames:',
150
        implode(',', $desc->output_file_names)
151
    );
152
    if (!empty($desc->max_total)) {
153
        row2('Max total instances per job:', $desc->max_total);
154
    } else {
155
        row2('Max total instances per job:', '1');
156
    }
157
    if (!empty($desc->min_nsuccess)) {
158
        row2('Target successful instances per job:', $desc->min_nsuccess);
159
    } else {
160
        row2('Target successful instances per job:', '1');
161
    }
162
    if (!empty($desc->max_delay_days)) {
163
        row2('Max job turnaround time, days:', $desc->max_delay_days);
164
    } else {
165
        row2('Max job turnaround time, days:', '7');
166
    }
167
    end_table();
168
169
    if ($manage_access) {
170
        echo '<p>';
171
        show_button_small(
172
            "buda.php?action=variant_form&app=$app&variant=$variant",
173
            'Edit variant'
174
        );
175
        echo '<p>';
176
        show_button(
177
            "buda.php?action=variant_delete&app=$app&variant=$variant",
178
            'Delete variant',
179
            null,
180
            'btn btn-xs btn-warning'
181
        );
182
    }
183
    page_tail();
184
}
185
186
// form for creating/editing app variant.
187
//
188
function variant_form($user) {
189
    $sbitems = sandbox_select_items($user);
190
    $app = get_str('app');
191
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
192
    $variant = get_str('variant', true);
193
194
    if ($variant) {
195
        global $buda_root;
196
        $variant_dir = "$buda_root/$app/$variant";
197
        $variant_desc = json_decode(
198
            file_get_contents("$variant_dir/variant.json")
199
        );
200
        if (!$variant_desc) error_page('no such variant');
201
        page_head_select2("Edit variant $variant of BUDA app $app");
202
    } else {
203
        $variant_desc = new StdClass;
204
        $variant_desc->dockerfile = '';
205
        $variant_desc->app_files = [];
206
        $variant_desc->input_file_names = [];
207
        $variant_desc->output_file_names = [];
208
        $variant_desc->min_nsuccess = 1;
209
        $variant_desc->max_total = 1;
210
        $variant_desc->max_delay_days = 7;
211
        page_head_select2("Create a variant of BUDA app $app");
212
    }
213
    echo "
214
        Details are <a href=https://github.com/BOINC/boinc/wiki/BUDA-job-submission#adding-a-variant>here</a>.
215
    ";
216
    $sb = '<br><small>From your <a href=sandbox.php>file sandbox</a></small>';
217
    $pc = '<br><small>Specify
218
    <a href=https://github.com/BOINC/boinc/wiki/AppPlan>GPU and other requirements</a>';
219
    form_start('buda.php');
220
    form_input_hidden('app', $app);
221
    form_input_hidden('action', 'variant_action');
222
    if ($variant) {
223
        form_input_hidden('variant', $variant);
224
        form_input_hidden('edit', 'true');
225
    } else {
226
        form_input_text("Plan class$pc", 'variant', $variant);
227
    }
228
    form_select("Dockerfile$sb", 'dockerfile', $sbitems, $variant_desc->dockerfile);
229
    form_select2_multi("Application files$sb", 'app_files', $sbitems, $variant_desc->app_files);
230
    form_input_text(
231
        'Input file names<br><small>Space-separated</small>',
232
        'input_file_names',
233
        implode(' ', $variant_desc->input_file_names)
234
    );
235
    form_input_text(
236
        'Output file names<br><small>Space-separated</small>',
237
        'output_file_names',
238
        implode(' ', $variant_desc->output_file_names)
239
    );
240
    form_input_text(
241
        'Run at most this many total instances of each job',
242
        'max_total',
243
        $variant_desc->max_total
244
    );
245
    form_input_text(
246
        'Get this many successful instances of each job
247
            <br><small>(subject to the above limit)</small>
248
        ',
249
        'min_nsuccess',
250
        $variant_desc->min_nsuccess
251
    );
252
    form_input_text(
253
        'Max job turnaround time, days',
254
        'max_delay_days',
255
        $variant_desc->max_delay_days
256
    );
257
    form_submit('OK');
258
    form_end();
259
    page_tail();
260
}
261
262
function buda_file_phys_name($app, $variant, $md5) {
263
    return sprintf('buda_%s_%s_%s', $app, $variant, $md5);
264
}
265
266
// copy file from sandbox to variant dir, and stage to download hier
267
//
268
function copy_and_stage_file($user, $fname, $dir, $app, $variant) {
269
    copy_sandbox_file($user, $fname, $dir);
270
    [$md5, $size] = parse_info_file("$dir/.md5/$fname");
271
    $phys_name = buda_file_phys_name($app, $variant, $md5);
272
    stage_file_aux("$dir/$fname", $md5, $size, $phys_name);
273
    return $phys_name;
274
}
275
276
// create templates and put them in variant dir
277
//
278
function create_templates($variant, $variant_desc, $dir) {
279
    // input template
280
    //
281
    $x = "<input_template>\n";
282
    $ninfiles = 1 + count($variant_desc->input_file_names) + count($variant_desc->app_files);
283
    for ($i=0; $i<$ninfiles; $i++) {
284
        $x .= "   <file_info>\n      <sticky/>\n      <no_delete/>\n      <executable/>\n   </file_info>\n";
285
    }
286
    $x .= "   <workunit>\n";
287
    $x .= file_ref_in($variant_desc->dockerfile);
288
    foreach ($variant_desc->app_files as $fname) {
289
        $x .= file_ref_in($fname);
290
    }
291
    foreach ($variant_desc->input_file_names as $fname) {
292
        $x .= file_ref_in($fname);
293
    }
294
    if (strstr($variant, 'cpu')) {
295
        $x .= "      <plan_class></plan_class>\n";
296
    } else {
297
        $x .= "      <plan_class>$variant</plan_class>\n";
298
    }
299
300
    // replication params
301
    //
302
    $x .= sprintf("      <target_nresults>%d</target_nresults>\n",
303
        $variant_desc->min_nsuccess
304
    );
305
    $x .= sprintf("      <min_quorum>%d</min_quorum>\n",
306
        $variant_desc->min_nsuccess
307
    );
308
    $x .= sprintf("      <max_total_results>%d</max_total_results>\n",
309
        $variant_desc->max_total
310
    );
311
312
    $x .= sprintf("      <max_delay>%f</max_delay>\n",
313
        $variant_desc->max_delay_days * 86400.
314
    );
315
316
    $x .= "   </workunit>\n<input_template>\n";
317
    file_put_contents("$dir/template_in", $x);
318
319
    // output template
320
    //
321
    $x = "<output_template>\n";
322
    $i = 0;
323
    foreach ($variant_desc->output_file_names as $fname) {
324
        $x .= file_info_out($i++);
325
    }
326
    $x .= "   <result>\n";
327
    $i = 0;
328
    foreach ($variant_desc->output_file_names as $fname) {
329
        $x .= file_ref_out($i++, $fname);
330
    }
331
    $x .= "   </result>\n</output_template>\n";
332
    file_put_contents("$dir/template_out", $x);
333
}
334
335
// create variant
336
//
337
function variant_action($user) {
338
    global $buda_root;
339
    $variant = get_str('variant');
340
    if (!$variant) $variant = 'cpu';
341
    if (!is_valid_filename($variant)) {
342
        error_page(filename_rules());
343
    }
344
    $app = get_str('app');
345
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
346
    $dockerfile = get_str('dockerfile');
347
    if (!is_valid_filename($dockerfile)) {
348
        error_page("Invalid dockerfile name: ".filename_rules());
349
    }
350
    $app_files = get_array('app_files');
351
    foreach ($app_files as $fname) {
352
        if (!is_valid_filename($fname)) {
353
            error_page("Invalid app file name: ".filename_rules());
354
        }
355
    }
356
    $min_nsuccess = get_int('min_nsuccess');
357
    if ($min_nsuccess <= 0) {
358
        error_page('Must specify a positive number of successful instances.');
359
    }
360
    $max_total = get_int('max_total');
361
    if ($max_total <= 0) {
362
        error_page('Must specify a positive max number of instances.');
363
    }
364
    if ($min_nsuccess > $max_total) {
365
        error_page('Target # of successful instances must be <= max total');
366
    }
367
    $max_delay_days = get_str('max_delay_days');
368
    if (!is_numeric($max_delay_days)) {
369
        error_page('Must specify max delay');
370
    }
371
    $max_delay_days = floatval($max_delay_days);
372
    if ($max_delay_days <= 0) {
373
        error_page('Must specify positive max delay');
374
    }
375
    $input_file_names = get_str('input_file_names', true);
376
    $output_file_names = explode(' ', get_str('output_file_names'));
377
    if ($input_file_names) {
378
        $input_file_names = explode(' ', $input_file_names);
379
        foreach ($input_file_names as $fname) {
380
            if (!is_valid_filename($fname)) {
381
                error_page("Invalid input file name: ".filename_rules());
382
            }
383
        }
384
    } else {
385
        $input_file_names = [];
386
    }
387
    foreach ($output_file_names as $fname) {
388
        if (!is_valid_filename($fname)) {
389
            error_page("Invalid output file name: ".filename_rules());
390
        }
391
    }
392
393
    $dir = "$buda_root/$app/$variant";
394
    if (get_str('edit', true)) {
395
        system("rm -r $dir");
396
    } else {
397
        if (file_exists($dir)) {
398
            error_page("Variant '$variant' already exists.");
399
        }
400
    }
401
    mkdir($dir);
402
    mkdir("$dir/.md5");
403
404
    // collect variant params into a struct
405
    //
406
    $desc = new StdClass;
407
    $desc->dockerfile = $dockerfile;
408
    $desc->app_files = $app_files;
409
    $desc->input_file_names = $input_file_names;
410
    $desc->output_file_names = $output_file_names;
411
    $desc->min_nsuccess = $min_nsuccess;
412
    $desc->max_total = $max_total;
413
    $desc->max_delay_days = $max_delay_days;
414
415
    // copy files from sandbox to variant dir
416
    //
417
    $pname = copy_and_stage_file($user, $dockerfile, $dir, $app, $variant);
418
    $desc->dockerfile_phys = $pname;
419
    $desc->app_files_phys = [];
420
    foreach ($app_files as $fname) {
421
        $pname = copy_and_stage_file($user, $fname, $dir, $app, $variant);
422
        $desc->app_files_phys[] = $pname;
423
    }
424
425
    // write variant params to a JSON file
426
    //
427
    file_put_contents(
428
        "$dir/variant.json",
429
        json_encode($desc, JSON_PRETTY_PRINT)
430
    );
431
432
    create_templates($variant, $desc, $dir);
433
434
    // Note: we don't currently allow indirect file access.
435
    // If we did, we'd need to create job.toml to mount project dir
436
437
    app_list("Variant $variant added for app $app.");
438
}
439
440
function variant_delete() {
441
    global $buda_root;
442
    $app = get_str('app');
443
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
444
    $variant = get_str('variant');
445
    if (!is_valid_filename($variant)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
446
    $confirmed = get_str('confirmed', true);
447
    if ($confirmed) {
448
        $dir = "$buda_root/$app/$variant";
449
        if (!file_exists($dir)) error_page('no such variant');
450
        // delete staged files
451
        //
452
        foreach (scandir("$dir/.md5") as $fname) {
453
            if ($fname[0] == '.') continue;
454
            [$md5, $size] = parse_info_file("$dir/.md5/$fname");
455
            $phys_name = buda_file_phys_name($app, $variant, $md5);
456
            $phys_path = download_hier_path($phys_name);
457
            unlink($phys_path);
458
            unlink("$phys_path.md5");
459
        }
460
        system("rm -r $buda_root/$app/$variant", $ret);
461
        if ($ret) {
462
            error_page("delete failed");
463
        }
464
        $notice = "Variant $variant of app $app removed.";
465
        app_list($notice);
466
    } else {
467
        page_head("Confirm");
468
        echo "<p>Are you sure you want to delete variant $variant of BUDA app $app?  <p>";
469
        show_button(
470
            "buda.php?action=variant_delete&app=$app&variant=$variant&confirmed=yes",
471
            "Yes"
472
        );
473
        page_tail();
474
    }
475
}
476
477
function app_delete() {
478
    global $buda_root;
479
    $app = get_str('app');
480
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
481
    $confirmed = get_str('confirmed', true);
482
    if ($confirmed) {
483
        $dir = "$buda_root/$app";
484
        if (!file_exists($dir)) error_page('no such app');
485
        $vars = get_buda_variants($app);
486
        if ($vars) {
487
            error_page("You must delete all variants first.");
488
        }
489
        system("rm $buda_root/$app/desc.json", $ret);
490
        system("rmdir $buda_root/$app", $ret);
491
        if ($ret) {
492
            error_page('delete failed');
493
        }
494
        $notice = "App $app removed.";
495
        app_list($notice);
496
    } else {
497
        page_head('Confirm');
498
        echo "<p>Are you sure you want to delete BUDA science app $app?  <p>";
499
        show_button(
500
            "buda.php?action=app_delete&app=$app&confirmed=yes",
501
            "Yes"
502
        );
503
        page_tail();
504
    }
505
}
506
507
function app_form($desc=null) {
508
    page_head_select2($desc?"Edit BUDA app $desc->name":'Create BUDA app');
509
    form_start('buda.php');
510
    form_input_hidden('action', 'app_action');
511
    if ($desc) {
512
        form_input_hidden('edit_name', $desc->name);
513
        form_input_hidden('user_id', $desc->user_id);
514
        form_input_hidden('create_time', $desc->create_time);
515
    } else {
516
        form_input_text('Internal name<br><small>No spaces</small>', 'name');
517
    }
518
    form_input_text('User-visible name', 'long_name',
519
        $desc?$desc->long_name:null
520
    );
521
    form_input_textarea(
522
        'Description<br><small>... of what the app does and of the research goals</small>',
523
        'description',
524
        $desc?$desc->description:null
525
    );
526
    form_select2_multi('Science keywords',
527
        'sci_kw',
528
        keyword_select_options(KW_CATEGORY_SCIENCE),
529
        $desc?$desc->sci_kw:null
530
    );
531
    form_input_text(
532
        'URL of web page describing app',
533
        'url',
534
        !empty($desc->url)?$desc->url:''
535
    );
536
    // don't include location keywords;
537
    // various people may submit jobs to this app
538
    form_submit('OK');
539
    form_end();
540
    page_tail();
541
}
542
543
function app_action($user) {
544
    global $buda_root;
545
    $edit_name = get_str('edit_name', true);
546
    $desc = new StdClass;
547
    if ($edit_name) {
548
        $dir = "$buda_root/$edit_name";
549
        $name = $edit_name;
550
        $desc->user_id = get_int('user_id');
551
        $desc->create_time = get_int('create_time');
552
    } else {
553
        $name = get_str('name');
554
        if (!is_valid_filename($name)) {
555
            error_page(filename_rules());
556
        }
557
        $dir = "$buda_root/$name";
558
        if (file_exists($dir)) {
559
            error_page("App $name already exists.");
560
        }
561
        mkdir($dir);
562
        $desc->user_id = $user->id;
563
        $desc->create_time = time();
564
    }
565
    $desc->name = $name;
566
    $desc->long_name = get_str('long_name');
567
    $desc->description = get_str('description');
568
    $desc->sci_kw = array_map('intval', get_array('sci_kw'));
569
    file_put_contents("$dir/desc.json", json_encode($desc, JSON_PRETTY_PRINT));
570
    header("Location: buda.php");
571
}
572
573
function view_file() {
574
    global $buda_root;
575
    $app = get_str('app');
576
    if (!is_valid_filename($app)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
577
    $variant = get_str('variant');
578
    if (!is_valid_filename($variant)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
579
    $fname = get_str('fname');
580
    if (!is_valid_filename($fname)) die('bad arg');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
581
    echo "<pre>\n";
582
    $x = file_get_contents("$buda_root/$app/$variant/$fname");
583
    echo htmlspecialchars($x);
584
    echo "</pre>\n";
585
}
586
587
function handle_app_edit() {
588
    global $buda_root;
589
    $name = get_str('name');
590
    app_form(get_buda_desc($name));
591
}
592
593
function app_details() {
594
    global $buda_root, $manage_access;
595
    $name = get_str('name');
596
    $desc = get_buda_desc($name);
597
    if (!$desc) error_page("no desc file $path");
598
    page_head("BUDA app: $desc->long_name");
599
    start_table();
600
    row2('Internal name', $desc->name);
601
    $user = BoincUser::lookup_id($desc->user_id);
602
    row2('Creator',
603
        sprintf('<a href=show_user.php?userid=%d>%s</a>',
604
            $user->id,
605
            $user->name
606
        )
607
    );
608
    row2('Created', date_str($desc->create_time));
609
    row2('Description', $desc->description);
610
    row2('Science keywords', kw_array_to_str($desc->sci_kw));
611
    if ($manage_access) {
612
        row2('',
613
            button_text_small(
614
                sprintf('buda.php?action=%s&name=%s', 'app_edit', $desc->name),
615
                'Edit app info'
616
            )
617
        );
618
    }
619
    $vars = get_buda_variants($name);
620
    if ($vars) {
621
        $x = [];
622
        foreach ($vars as $var) {
623
            $x[] = sprintf('<a href=buda.php?action=variant_view&app=%s&variant=%s>%s</a>',
624
                $name, $var, $var
625
            );
626
        }
627
        row2('Variants', implode('<p>', $x));
628
        if ($manage_access) {
629
            row2('',
630
                button_text_small(
631
                    "buda.php?action=variant_form&app=$name",
632
                    'Add variant'
633
                )
634
            );
635
        }
636
    } else if ($manage_access) {
637
        row2('Variants',
638
            button_text_small(
639
                "buda.php?action=variant_form&app=$name",
640
                'Add variant'
641
            )
642
        );
643
        row2('',
644
            button_text(
645
                "buda.php?action=app_delete&app=$name",
646
                "Delete app",
647
                null,
648
                'btn btn-xs btn-warning'
649
            )
650
        );
651
    }
652
    end_table();
653
    page_tail();
654
}
655
656
// Users with manage access to BUDA can add/delete apps and variants.
657
// Others can just view.
658
// Might want to refine this at some point
659
660
$user = get_logged_in_user();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $user is correct as get_logged_in_user() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
661
$buda_app = BoincApp::lookup("name='buda'");
662
if (!$buda_app) error_page('no buda app');
663
$manage_access = has_manage_access($user, $buda_app->id);
664
665
$action = get_str('action', true);
666
switch ($action) {
667
case 'app_edit':
668
    if (!$manage_access) error_page('no access');
669
    handle_app_edit(); break;
670
case 'app_form':
671
    if (!$manage_access) error_page('no access');
672
    app_form(); break;
673
case 'app_action':
674
    if (!$manage_access) error_page('no access');
675
    app_action($user); break;
676
case 'app_details':
677
    app_details(); break;
678
case 'app_delete':
679
    if (!$manage_access) error_page('no access');
680
    app_delete(); break;
681
case 'variant_view':
682
    variant_view($user); break;
0 ignored issues
show
Unused Code introduced by
The call to variant_view() has too many arguments starting with $user. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

682
    /** @scrutinizer ignore-call */ 
683
    variant_view($user); break;

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
683
case 'variant_form':
684
    if (!$manage_access) error_page('no access');
685
    variant_form($user); break;
686
case 'variant_action':
687
    if (!$manage_access) error_page('no access');
688
    variant_action($user);
689
    write_plan_class_file();
690
    break;
691
case 'variant_delete':
692
    if (!$manage_access) error_page('no access');
693
    variant_delete();
694
    write_plan_class_file();
695
    break;
696
case 'view_file':
697
    view_file(); break;
698
case null:
699
    app_list(); break;
700
default:
0 ignored issues
show
Coding Style introduced by
DEFAULT keyword must be indented 4 spaces from SWITCH keyword
Loading history...
Coding Style introduced by
DEFAULT case must have a breaking statement
Loading history...
701
    error_page("unknown action");
702
}
703
704
?>
705