Completed
Push — master ( 279b7a...65d2af )
by David
49s queued 15s
created

app_details()   C

Complexity

Conditions 10
Paths 128

Size

Total Lines 84
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 63
c 0
b 0
f 0
nc 128
nop 0
dl 0
loc 84
rs 6.7539

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
// show list of BUDA apps and variants,
37
// w/ buttons for adding and deleting
38
//
39
function app_list($notice=null) {
40
    global $buda_root;
41
    if (!is_dir($buda_root)) {
42
        mkdir($buda_root);
43
    }
44
    page_head('Manage BUDA apps');
45
    if ($notice) {
46
        echo "$notice <p>\n";
47
    }
48
    text_start();
49
    echo "
50
        <p>BUDA lets you submit Docker jobs using a web interface.
51
        <a href=https://github.com/BOINC/boinc/wiki/BUDA-overview>Learn more</a>.
52
        <p>
53
        <h3>BUDA science apps</h3>
54
    ";
55
56
    $apps = get_buda_apps();
57
    foreach ($apps as $app) {
58
        show_app($app);
59
    }
60
    echo '<hr>';
61
    show_button_small('buda.php?action=app_form', 'Add science app');
62
    text_end();
63
    page_tail();
64
}
65
66
function show_app($app_dir) {
67
    global $buda_root;
68
    $desc = null;
69
    $desc_path = "$buda_root/$app_dir/desc.json";
70
    $desc = json_decode(file_get_contents($desc_path));
71
    echo '<hr>';
72
    echo sprintf('<h3>%s</h3><p>', $desc->long_name);
73
    show_button_small(
74
        sprintf('buda.php?action=app_details&name=%s', $desc->name),
75
        'App details'
76
    );
77
    $var_dirs = get_buda_variants($app_dir);
78
    if ($var_dirs) {
79
        echo "<p>Variants:<ul>";
80
        foreach ($var_dirs as $var_dir) {
81
            $var_desc = get_buda_var_desc($app_dir, $var_dir);
82
            echo sprintf(
83
                '<li><a href=buda.php?action=variant_view&app=%s&variant=%s>%s</a>',
84
                $app_dir, $var_dir, variant_name($var_desc)
85
            );
86
        }
87
        echo '</ul>';
88
    } else {
89
        echo '<p>No variants';
90
    }
91
    echo "<p>";
92
}
93
94
function file_row($app, $variant, $dir, $f) {
95
    [$md5, $size] = parse_info_file("$dir/.md5/$f");
96
    table_row(
97
        "<a href=buda.php?action=view_file&app=$app&variant=$variant&fname=$f>$f</a>",
98
        $size,
99
        $md5
100
    );
101
}
102
103
function variant_view() {
104
    global $buda_root, $manage_access;
105
    $app = get_str('app');
106
    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...
107
    $variant = get_str('variant');
108
    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...
109
    page_head("BUDA variant");
110
    $dir = "$buda_root/$app/$variant";
111
    $desc = json_decode(file_get_contents("$dir/variant.json"));
112
    start_table('table-striped');
113
    row2("BUDA App", $app);
114
    row2("Variant name", $variant);
115
    row2("CPU type", $desc->cpu_type);
116
    row2("Plan class", $desc->plan_class);
117
    end_table();
118
    echo "<h3>App files</h3>";
119
    start_table();
120
    table_header('Dockerfile', 'size', 'md5');
121
    file_row($app, $variant, $dir, $desc->dockerfile);
122
    table_header('App files', '', '');
123
    foreach ($desc->app_files as $f) {
124
        file_row($app, $variant, $dir, $f);
125
    }
126
    table_header('Auto-generated files', '', '');
127
    file_row($app, $variant, $dir, 'variant.json');
128
    end_table();
129
    echo '<hr>';
130
131
    if ($manage_access) {
132
        echo '<p>';
133
        show_button_small(
134
            "buda.php?action=variant_form&app=$app&variant=$variant",
135
            'Edit variant'
136
        );
137
        echo '<p>';
138
        show_button(
139
            "buda.php?action=variant_delete&app=$app&variant=$variant",
140
            'Delete variant',
141
            null,
142
            'btn btn-xs btn-warning'
143
        );
144
    }
145
    page_tail();
146
}
147
148
// form for creating an app variant or editing an existing one
149
//
150
function variant_form($user) {
151
    $sbitems = sandbox_select_items($user);
152
    $app = get_str('app');
153
    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...
154
155
    // name of variant directory, if we're editing
156
    $variant = get_str('variant', true);
157
158
    if ($variant) {
159
        global $buda_root;
160
        $variant_dir = "$buda_root/$app/$variant";
161
        $variant_desc = json_decode(
162
            file_get_contents("$variant_dir/variant.json")
163
        );
164
        if (!$variant_desc) error_page('no such variant');
165
        page_head_select2("Edit variant $variant of BUDA app $app");
166
    } else {
167
        $variant_desc = new StdClass;
168
        $variant_desc->cpu_type = 'intel';
169
        $variant_desc->plan_class = '';
170
        $variant_desc->dockerfile = '';
171
        $variant_desc->app_files = [];
172
        page_head_select2("Create a variant of BUDA app $app");
173
    }
174
    echo "
175
        Details are <a href=https://github.com/BOINC/boinc/wiki/BUDA-job-submission#adding-a-variant>here</a>.
176
    ";
177
    $sb = '<br><small>From your <a href=sandbox.php>file sandbox</a></small>';
178
    $pc = '<br><small>Specify
179
    <a href=https://github.com/BOINC/boinc/wiki/AppPlan>GPU and other host requirements</a>.<br>Leave blank if none.</small>';
180
    form_start('buda.php');
181
    form_input_hidden('app', $app);
182
    form_input_hidden('action', 'variant_action');
183
    if ($variant) {
184
        // can't change CPU type of existing variant
185
        form_input_hidden('variant', $variant);
186
        form_input_hidden('edit', 'true');
187
    } else {
188
        form_radio_buttons(
189
            'CPU type', 'cpu_type',
190
            [
191
                ['intel', 'Intel'],
192
                ['arm', 'ARM']
0 ignored issues
show
Coding Style introduced by
There should be a trailing comma after the last value of an array declaration.
Loading history...
193
            ],
194
            $variant_desc->cpu_type
195
        );
196
    }
197
    form_input_text("Plan class$pc", 'plan_class', $variant_desc->plan_class);
198
    form_select("Dockerfile$sb", 'dockerfile', $sbitems, $variant_desc->dockerfile);
199
    form_select2_multi("Application files$sb", 'app_files', $sbitems, $variant_desc->app_files);
200
    form_submit('OK');
201
    form_end();
202
    page_tail();
203
}
204
205
function buda_file_phys_name($app, $variant, $md5) {
206
    return sprintf('buda_%s_%s_%s', $app, $variant, $md5);
207
}
208
209
// copy file from sandbox to variant dir, and stage to download hier
210
// return physical name, md5, and size
211
//
212
function copy_and_stage_file($user, $fname, $variant_dir, $app, $variant) {
213
    copy_sandbox_file($user, $fname, $variant_dir);
214
    [$md5, $size] = parse_info_file("$variant_dir/.md5/$fname");
215
    $phys_name = buda_file_phys_name($app, $variant, $md5);
216
    stage_file_aux("$variant_dir/$fname", $md5, $size, $phys_name);
217
    return [$phys_name, $md5, $size];
218
}
219
220
// create templates and put them in app dir
221
//
222
function create_templates($app, $desc, $dir) {
223
    // input template
224
    //
225
    $x = "<input_template>\n";
226
    $ninfiles = count($desc->input_file_names);
227
    for ($i=0; $i<$ninfiles; $i++) {
228
        $x .= "   <file_info>\n      <sticky/>\n      <no_delete/>\n      <executable/>\n   </file_info>\n";
229
    }
230
    $x .= "   <workunit>\n";
231
    foreach ($desc->input_file_names as $fname) {
232
        $x .= file_ref_in($fname);
233
    }
234
235
    // replication params
236
    //
237
    $x .= sprintf("      <target_nresults>%d</target_nresults>\n",
238
        $desc->min_nsuccess
239
    );
240
    $x .= sprintf("      <min_quorum>%d</min_quorum>\n",
241
        $desc->min_nsuccess
242
    );
243
    $x .= sprintf("      <max_total_results>%d</max_total_results>\n",
244
        $desc->max_total
245
    );
246
247
    $x .= sprintf("      <max_delay>%f</max_delay>\n",
248
        $desc->max_delay_days * 86400.
249
    );
250
251
    $x .= "      <buda_app_name>$app</buda_app_name>\n";
252
    $x .= "   </workunit>\n</input_template>\n";
253
    file_put_contents("$dir/template_in", $x);
254
255
    // output template
256
    //
257
    $x = "<output_template>\n";
258
    $i = 0;
259
    foreach ($desc->output_file_names as $fname) {
260
        $x .= file_info_out($i++);
261
    }
262
    $x .= "   <result>\n";
263
    $i = 0;
264
    foreach ($desc->output_file_names as $fname) {
265
        $x .= file_ref_out($i++, $fname);
266
    }
267
    $x .= "   </result>\n</output_template>\n";
268
    file_put_contents("$dir/template_out", $x);
269
}
270
271
// return <file_info> and <file_ref> elements for given file
272
//
273
function file_xml_elements($log_name, $phys_name, $md5, $nbytes) {
274
    static $download_dir, $download_url, $fanout;
275
    if ($download_dir == null) {
276
        $download_dir = parse_element(get_config(), "<download_dir>");
277
        $download_url = parse_element(get_config(), "<download_url>");
278
        $fanout = (int)(parse_element(get_config(), "<uldl_dir_fanout>"));
279
    }
280
    $file_info = sprintf(
281
"<file_info>
282
    <sticky/>
283
    <no_delete/>
284
    <executable/>
285
    <name>%s</name>
286
    <url>%s/%s/%s</url>
287
    <md5_cksum>%s</md5_cksum>
288
    <nbytes>%d</nbytes>
289
</file_info>
290
",
291
        $phys_name,
292
        $download_url, filename_hash($phys_name, $fanout), $phys_name,
293
        $md5,
294
        $nbytes
295
    );
296
    $file_ref = sprintf(
297
"<file_ref>
298
    <file_name>%s</file_name>
299
    <open_name>%s</open_name>
300
    <copy_file/>
301
</file_ref>
302
",
303
        $phys_name,
304
        $log_name
305
    );
306
    return [$file_info, $file_ref];
307
}
308
309
// create variant
310
//
311
function variant_action($user) {
312
    global $buda_root;
313
    $cpu_type = get_str('cpu_type');
314
    $plan_class = get_str('plan_class');
315
    $variant = get_str('variant', true);
316
    if ($variant) {
317
        $creating = false;
318
    } else {
319
        $creating = true;
320
    }
321
    $variant = sprintf('%s_%s', $cpu_type, $plan_class?$plan_class:'cpu');
322
    if (!is_valid_filename($variant)) {
323
        error_page(filename_rules());
324
    }
325
    $app = get_str('app');
326
    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...
327
328
    $dockerfile = get_str('dockerfile');
329
    if (!is_valid_filename($dockerfile)) {
330
        error_page("Invalid dockerfile name: ".filename_rules());
331
    }
332
    $app_files = get_array('app_files');
333
    foreach ($app_files as $fname) {
334
        if (!is_valid_filename($fname)) {
335
            error_page("Invalid app file name: ".filename_rules());
336
        }
337
    }
338
339
    $dir = "$buda_root/$app/$variant";
340
    if ($creating) {
341
        if (file_exists($dir)) {
342
            error_page("Variant '$variant' already exists.");
343
        }
344
    } else {
345
        system("rm -r $dir");
346
    }
347
    mkdir($dir);
348
    mkdir("$dir/.md5");
349
350
    // collect variant params into a struct
351
    //
352
    $desc = new StdClass;
353
    $desc->dockerfile = $dockerfile;
354
    $desc->app_files = $app_files;
355
    $desc->cpu_type = $cpu_type;
356
    $desc->plan_class = $plan_class;
357
    $desc->file_infos = '';
358
    $desc->file_refs = '';
359
360
    // copy dockerfile and app files from sandbox to variant dir,
361
    // and stage them to download dir
362
    //
363
    [$pname, $md5, $nbytes] = copy_and_stage_file(
364
        $user, $dockerfile, $dir, $app, $variant
365
    );
366
    $desc->dockerfile_phys = $pname;
367
    $desc->app_files_phys = [];
368
    [$file_info, $file_ref] = file_xml_elements(
369
        'Dockerfile', $pname, $md5, $nbytes
370
    );
371
    $desc->file_infos .= $file_info;
372
    $desc->file_refs .= $file_ref;
373
374
    foreach ($app_files as $fname) {
375
        [$pname, $md5, $nbytes] = copy_and_stage_file(
376
            $user, $fname, $dir, $app, $variant
377
        );
378
        $desc->app_files_phys[] = $pname;
379
        [$file_info, $file_ref] = file_xml_elements(
380
            $fname, $pname, $md5, $nbytes
381
        );
382
        $desc->file_infos .= $file_info;
383
        $desc->file_refs .= $file_ref;
384
    }
385
386
    // write variant params to a JSON file
387
    //
388
    file_put_contents(
389
        "$dir/variant.json",
390
        json_encode($desc, JSON_PRETTY_PRINT)
391
    );
392
393
    // Note: we don't currently allow indirect file access.
394
    // If we did, we'd need to create job.toml to mount project dir
395
396
    app_list("Variant $variant added for app $app.");
397
}
398
399
function variant_delete() {
400
    global $buda_root;
401
    $app = get_str('app');
402
    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...
403
    $variant = get_str('variant');
404
    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...
405
    $confirmed = get_str('confirmed', true);
406
    if ($confirmed) {
407
        $dir = "$buda_root/$app/$variant";
408
        if (!file_exists($dir)) error_page('no such variant');
409
        // delete staged files
410
        //
411
        foreach (scandir("$dir/.md5") as $fname) {
412
            if ($fname[0] == '.') continue;
413
            [$md5, $size] = parse_info_file("$dir/.md5/$fname");
414
            $phys_name = buda_file_phys_name($app, $variant, $md5);
415
            $phys_path = download_hier_path($phys_name);
416
            unlink($phys_path);
417
            unlink("$phys_path.md5");
418
        }
419
        system("rm -r $buda_root/$app/$variant", $ret);
420
        if ($ret) {
421
            error_page("delete failed");
422
        }
423
        $notice = "Variant $variant of app $app removed.";
424
        app_list($notice);
425
    } else {
426
        page_head("Confirm");
427
        echo "<p>Are you sure you want to delete variant $variant of BUDA app $app?  <p>";
428
        show_button(
429
            "buda.php?action=variant_delete&app=$app&variant=$variant&confirmed=yes",
430
            "Yes"
431
        );
432
        page_tail();
433
    }
434
}
435
436
function app_delete() {
437
    global $buda_root;
438
    $app = get_str('app');
439
    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...
440
    $confirmed = get_str('confirmed', true);
441
    if ($confirmed) {
442
        $dir = "$buda_root/$app";
443
        if (!file_exists($dir)) error_page('no such app');
444
        $vars = get_buda_variants($app);
445
        if ($vars) {
446
            error_page("You must delete all variants first.");
447
        }
448
        system("rm $buda_root/$app/desc.json", $ret);
449
        system("rmdir $buda_root/$app", $ret);
450
        if ($ret) {
451
            error_page('delete failed');
452
        }
453
        $notice = "App $app removed.";
454
        app_list($notice);
455
    } else {
456
        page_head('Confirm');
457
        echo "<p>Are you sure you want to delete BUDA science app $app?  <p>";
458
        show_button(
459
            "buda.php?action=app_delete&app=$app&confirmed=yes",
460
            "Yes"
461
        );
462
        page_tail();
463
    }
464
}
465
466
function app_form($desc=null) {
467
    page_head_select2($desc?"Edit BUDA app $desc->name":'Create BUDA app');
468
    form_start('buda.php');
469
    form_input_hidden('action', 'app_action');
470
    if ($desc) {
471
        form_input_hidden('edit_name', $desc->name);
472
        form_input_hidden('user_id', $desc->user_id);
473
        form_input_hidden('create_time', $desc->create_time);
474
    } else {
475
        $desc = new StdClass;
476
        $desc->long_name = null;
477
        $desc->input_file_names = [];
478
        $desc->output_file_names = [];
479
        $desc->min_nsuccess = 1;
480
        $desc->max_total = 2;
481
        $desc->max_delay_days = 7;
482
        $desc->description = null;
483
        $desc->sci_kw = null;
484
        $desc->url = null;
485
        form_input_text('Internal name<br><small>No spaces</small>', 'name');
486
    }
487
    form_input_text('User-visible name', 'long_name', $desc->long_name);
488
    form_input_text(
489
        'Input file names<br><small>Space-separated</small>',
490
        'input_file_names',
491
        implode(' ', $desc->input_file_names)
492
    );
493
    form_input_text(
494
        'Output file names<br><small>Space-separated</small>',
495
        'output_file_names',
496
        implode(' ', $desc->output_file_names)
497
    );
498
    form_input_text(
499
        'Run at most this many total instances of each job',
500
        'max_total',
501
        $desc->max_total
502
    );
503
    form_input_text(
504
        'Get this many successful instances of each job
505
            <br><small>(subject to the above limit)</small>
506
        ',
507
        'min_nsuccess',
508
        $desc->min_nsuccess
509
    );
510
    form_input_text(
511
        'Max job turnaround time, days',
512
        'max_delay_days',
513
        $desc->max_delay_days
514
    );
515
    form_input_textarea(
516
        'Description<br><small>... of what the app does and of the research goals</small>',
517
        'description',
518
        $desc->description
519
    );
520
    form_select2_multi('Science keywords',
521
        'sci_kw',
522
        keyword_select_options(KW_CATEGORY_SCIENCE),
523
        $desc->sci_kw
524
    );
525
    // don't include location keywords;
526
    // various people may submit jobs to this app
527
    form_submit('OK');
528
    form_end();
529
    page_tail();
530
}
531
532
function app_action($user) {
533
    global $buda_root;
534
    $edit_name = get_str('edit_name', true);
535
    $desc = new StdClass;
536
    if ($edit_name) {
537
        // editing existing app
538
        $dir = "$buda_root/$edit_name";
539
        $app_name = $edit_name;
540
        $desc->user_id = get_int('user_id');
541
        $desc->create_time = get_int('create_time');
542
    } else {
543
        // creating new app
544
        $app_name = get_str('name');
545
        if (!is_valid_filename($app_name)) {
546
            error_page(filename_rules());
547
        }
548
        $dir = "$buda_root/$app_name";
549
        if (file_exists($dir)) {
550
            error_page("App $app_name already exists.");
551
        }
552
        mkdir($dir);
553
        $desc->user_id = $user->id;
554
        $desc->create_time = time();
555
    }
556
    $desc->name = $app_name;
557
    $min_nsuccess = get_int('min_nsuccess');
558
    if ($min_nsuccess <= 0) {
559
        error_page('Must specify a positive number of successful instances.');
560
    }
561
    $max_total = get_int('max_total');
562
    if ($max_total <= 0) {
563
        error_page('Must specify a positive max number of instances.');
564
    }
565
    if ($min_nsuccess > $max_total) {
566
        error_page('Target # of successful instances must be <= max total');
567
    }
568
    $max_delay_days = get_str('max_delay_days');
569
    if (!is_numeric($max_delay_days)) {
570
        error_page('Must specify max delay');
571
    }
572
    $max_delay_days = floatval($max_delay_days);
573
    if ($max_delay_days <= 0) {
574
        error_page('Must specify positive max delay');
575
    }
576
577
    $input_file_names = get_str('input_file_names', true);
578
    if ($input_file_names) {
579
        $input_file_names = explode(' ', $input_file_names);
580
        foreach ($input_file_names as $fname) {
581
            if (!is_valid_filename($fname)) {
582
                error_page("Invalid input file name: ".filename_rules());
583
            }
584
        }
585
    } else {
586
        $input_file_names = [];
587
    }
588
    $output_file_names = get_str('output_file_names', true);
589
    if ($output_file_names) {
590
        $output_file_names = explode(' ', $output_file_names);
591
        foreach ($output_file_names as $fname) {
592
            if (!is_valid_filename($fname)) {
593
                error_page("Invalid output file name: ".filename_rules());
594
            }
595
        }
596
    } else {
597
        $output_file_names = [];
598
    }
599
    $desc->long_name = get_str('long_name');
600
    $desc->input_file_names = $input_file_names;
601
    $desc->output_file_names = $output_file_names;
602
    $desc->min_nsuccess = $min_nsuccess;
603
    $desc->max_total = $max_total;
604
    $desc->max_delay_days = $max_delay_days;
605
    $desc->description = get_str('description');
606
    $desc->sci_kw = array_map('intval', get_array('sci_kw'));
607
    file_put_contents("$dir/desc.json", json_encode($desc, JSON_PRETTY_PRINT));
608
609
    create_templates($app_name, $desc, $dir);
610
611
    header("Location: buda.php");
612
}
613
614
function view_file() {
615
    global $buda_root;
616
    $app = get_str('app');
617
    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...
618
    $variant = get_str('variant');
619
    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...
620
    $fname = get_str('fname');
621
    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...
622
    echo "<pre>\n";
623
    $x = file_get_contents("$buda_root/$app/$variant/$fname");
624
    echo htmlspecialchars($x);
625
    echo "</pre>\n";
626
}
627
628
function handle_app_edit() {
629
    global $buda_root;
630
    $name = get_str('name');
631
    app_form(get_buda_app_desc($name));
632
}
633
634
function app_details() {
635
    global $buda_root, $manage_access;
636
    $name = get_str('name');
637
    $desc = get_buda_app_desc($name);
638
    if (!$desc) error_page("no desc file $path");
639
    page_head("BUDA app: $desc->long_name");
640
    start_table('table-striped');
641
    row2('Internal name', $desc->name);
642
    $user = BoincUser::lookup_id($desc->user_id);
643
    row2('Creator',
644
        sprintf('<a href=show_user.php?userid=%d>%s</a>',
645
            $user->id,
646
            $user->name
647
        )
648
    );
649
    row2('Created', date_str($desc->create_time));
650
    row2('Description', $desc->description);
651
    row2('Science keywords', kw_array_to_str($desc->sci_kw));
652
    row2(
653
        'Input filenames:',
654
        implode(',', $desc->input_file_names)
655
    );
656
    row2(
657
        'Output filenames:',
658
        implode(',', $desc->output_file_names)
659
    );
660
    if (!empty($desc->max_total)) {
661
        row2('Max total instances per job:', $desc->max_total);
662
    } else {
663
        row2('Max total instances per job:', '1');
664
    }
665
    if (!empty($desc->min_nsuccess)) {
666
        row2('Target successful instances per job:', $desc->min_nsuccess);
667
    } else {
668
        row2('Target successful instances per job:', '1');
669
    }
670
    if (!empty($desc->max_delay_days)) {
671
        row2('Max job turnaround time, days:', $desc->max_delay_days);
672
    } else {
673
        row2('Max job turnaround time, days:', '7');
674
    }
675
    if ($manage_access) {
676
        row2('',
677
            button_text_small(
678
                sprintf('buda.php?action=%s&name=%s', 'app_edit', $desc->name),
679
                'Edit app info'
680
            )
681
        );
682
    }
683
    $vars = get_buda_variants($name);
684
    if ($vars) {
685
        $x = [];
686
        foreach ($vars as $var) {
687
            $x[] = sprintf('<a href=buda.php?action=variant_view&app=%s&variant=%s>%s</a>',
688
                $name, $var, $var
689
            );
690
        }
691
        row2('Variants', implode('<p>', $x));
692
        if ($manage_access) {
693
            row2('',
694
                button_text_small(
695
                    "buda.php?action=variant_form&app=$name",
696
                    'Add variant'
697
                )
698
            );
699
        }
700
    } else if ($manage_access) {
701
        row2('Variants',
702
            button_text_small(
703
                "buda.php?action=variant_form&app=$name",
704
                'Add variant'
705
            )
706
        );
707
        row2('',
708
            button_text(
709
                "buda.php?action=app_delete&app=$name",
710
                "Delete app",
711
                null,
712
                'btn btn-xs btn-warning'
713
            )
714
        );
715
    }
716
    end_table();
717
    page_tail();
718
}
719
720
// Users with manage access to BUDA can add/delete apps and variants.
721
// Others can just view.
722
// Might want to refine this at some point
723
724
$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...
725
$buda_app = BoincApp::lookup("name='buda'");
726
if (!$buda_app) error_page('no buda app');
727
$manage_access = has_manage_access($user, $buda_app->id);
728
729
$action = get_str('action', true);
730
switch ($action) {
731
case 'app_edit':
732
    if (!$manage_access) error_page('no access');
733
    handle_app_edit(); break;
734
case 'app_form':
735
    if (!$manage_access) error_page('no access');
736
    app_form(); break;
737
case 'app_action':
738
    if (!$manage_access) error_page('no access');
739
    app_action($user); break;
740
case 'app_details':
741
    app_details(); break;
742
case 'app_delete':
743
    if (!$manage_access) error_page('no access');
744
    app_delete(); break;
745
case 'variant_view':
746
    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

746
    /** @scrutinizer ignore-call */ 
747
    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...
747
case 'variant_form':
748
    if (!$manage_access) error_page('no access');
749
    variant_form($user); break;
750
case 'variant_action':
751
    if (!$manage_access) error_page('no access');
752
    variant_action($user);
753
    break;
754
case 'variant_delete':
755
    if (!$manage_access) error_page('no access');
756
    variant_delete();
757
    break;
758
case 'view_file':
759
    view_file(); break;
760
case null:
761
    app_list(); break;
762
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...
763
    error_page("unknown action");
764
}
765
766
?>
767