Skip to content

Commit 6c0a3aa

Browse files
authored
Merge pull request #1028 from biigle/merge-reports-module
Merge reports module
2 parents 7cd5e5b + 022289d commit 6c0a3aa

File tree

170 files changed

+19182
-15
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

170 files changed

+19182
-15
lines changed

app/AnnotationLabel.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* @property int $annotation_id
1111
* @property int $user_id
1212
* @property int $label_id
13+
* @property \Carbon\Carbon $created_at
1314
*/
1415
abstract class AnnotationLabel extends Model
1516
{
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace Biigle\Http\Controllers\Api;
4+
5+
use Biigle\Http\Requests\StoreProjectReport;
6+
use Biigle\Jobs\GenerateReportJob;
7+
use Biigle\Report;
8+
9+
class ProjectReportController extends Controller
10+
{
11+
/**
12+
* Generate a project report.
13+
*
14+
* @api {post} projects/:id/reports Request a project report
15+
* @apiGroup Reports
16+
* @apiName GenerateProjectReport
17+
*
18+
* @apiParam {Number} id The project ID.
19+
*
20+
* @apiParam (Required arguments) {Number} type_id The report type ID.
21+
*
22+
* @apiParam (Optional arguments) {Boolean} export_area If `true`, restrict the report to the export area of the project. Only available for image annotation reports and the iFDO report.
23+
* @apiParam (Optional arguments) {Boolean} newest_label If `true`, restrict the report to the newest label of each annotation.
24+
* @apiParam (Optional arguments) {Boolean} separate_label_trees If `true`, separate annotations with labels of different label trees to different files or sheets of the spreadsheet. Cannot be used together with `separate_users`. Not available for the iFDO report.
25+
* @apiParam (Optional arguments) {Boolean} separate_users If `true`, separate annotations with labels of different users to different files or sheets of the spreadsheet. Cannot be used together with `separate_label_trees`. Not available for the iFDO report.
26+
* @apiParam (Optional arguments) {Number[]} only_labels Array of label IDs to restrict the report to. Omit or leave empty to take all labels.
27+
* @apiParam (Optional arguments) {Boolean} aggregate_child_labels If `true`, add the abundance of child labels to the abundance of their parent labels and omit the child labels. This is only valid for the abundance report. Labels that are excluded with `only_labels` are not counted.
28+
* @apiParam (Optional arguments) {Boolean} disable_notifications If `true`, suppress notification to the user on report completion.
29+
* @apiParam (Optional arguments) {Boolean} strip_ifdo If `true`, remove annotation information from the original iFDO file before it is populated with BIIGLE annotations. Only available for the iFDO report.
30+
*
31+
* @apiPermission projectMember
32+
*
33+
* @param StoreProjectReport $request
34+
* @param int $id Project ID
35+
*
36+
* @return mixed
37+
*/
38+
public function store(StoreProjectReport $request, $id)
39+
{
40+
$report = new Report;
41+
$report->source()->associate($request->project);
42+
$report->type_id = $request->input('type_id');
43+
$report->user()->associate($request->user());
44+
$report->options = $request->getOptions();
45+
$report->save();
46+
47+
$queue = config('reports.generate_report_queue');
48+
GenerateReportJob::dispatch($report)->onQueue($queue);
49+
50+
if ($this->isAutomatedRequest()) {
51+
return $report;
52+
}
53+
}
54+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace Biigle\Http\Controllers\Api;
4+
5+
use Biigle\Report;
6+
use Illuminate\Http\Response;
7+
use Storage;
8+
9+
class ReportsController extends Controller
10+
{
11+
/**
12+
* @apiDefine reportOwner Report Owner
13+
* The user must be the owner of the report.
14+
*/
15+
16+
/**
17+
* Shows the specified report file.
18+
*
19+
* @api {get} reports/:id Get a report file
20+
* @apiGroup Reports
21+
* @apiName ShowReport
22+
* @apiPermission reportOwner
23+
* @apiDescription Responds with the file.
24+
*
25+
* @apiParam {Number} id The report ID.
26+
*
27+
* @param int $id report id
28+
* @return mixed
29+
*/
30+
public function show($id)
31+
{
32+
$report = Report::findOrFail($id);
33+
$this->authorize('access', $report);
34+
$report->touch();
35+
36+
$disk = Storage::disk(config('reports.storage_disk'));
37+
38+
if (!$disk->exists($report->getStorageFilename())) {
39+
abort(Response::HTTP_NOT_FOUND);
40+
}
41+
42+
$path = $report->getStorageFilename();
43+
return $disk->download($path, $report->filename)
44+
// Use a custom fallback with fread() because the default fpassthru() could
45+
// lead to an out of memory error with large reports.
46+
->setCallback(function () use ($disk, $path) {
47+
$stream = $disk->readStream($path);
48+
while (!feof($stream)) {
49+
echo fread($stream, 8192);
50+
}
51+
fclose($stream);
52+
});
53+
}
54+
55+
/**
56+
* Delete a report.
57+
*
58+
* @api {delete} reports/:id Delete a report
59+
* @apiGroup Reports
60+
* @apiName DestroyReport
61+
* @apiPermission reportOwner
62+
*
63+
* @apiParam {Number} id The report ID.
64+
*
65+
* @param int $id report id
66+
* @return mixed
67+
*/
68+
public function destroy($id)
69+
{
70+
$report = Report::findOrFail($id);
71+
$this->authorize('destroy', $report);
72+
$report->delete();
73+
74+
if (!$this->isAutomatedRequest()) {
75+
return $this->fuzzyRedirect()
76+
->with('message', 'Report deleted.')
77+
->with('messageType', 'success');
78+
}
79+
}
80+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Biigle\Http\Controllers\Api;
4+
5+
use Biigle\Http\Requests\StoreVolumeReport;
6+
use Biigle\Jobs\GenerateReportJob;
7+
use Biigle\Report;
8+
9+
class VolumeReportController extends Controller
10+
{
11+
/**
12+
* Generate a volume report.
13+
*
14+
* @api {post} volumes/:id/reports Request a volume report
15+
* @apiGroup Reports
16+
* @apiName GenerateVolumeReport
17+
* @apiDescription Accepts only requests for annotation and image label reports.
18+
*
19+
* @apiParam {Number} id The volume ID.
20+
*
21+
* @apiParam (Required arguments) {Number} type_id The report type ID.
22+
*
23+
* @apiParam (Optional arguments) {Boolean} export_area If `true`, restrict the report to the export area of the volume. Only available for image annotation reports and the iFDO report.
24+
* @apiParam (Optional arguments) {Boolean} newest_label If `true`, restrict the report to the newest label of each annotation.
25+
* @apiParam (Optional arguments) {Boolean} separate_label_trees If `true`, separate annotations with labels of different label trees to different files or sheets of the spreadsheet. Cannot be used together with `separate_users`. Not available for the iFDO report.
26+
* @apiParam (Optional arguments) {Boolean} separate_users If `true`, separate annotations with labels of different users to different files or sheets of the spreadsheet. Cannot be used together with `separate_label_trees`. Not available for the iFDO report.
27+
* @apiParam (Optional arguments) {Number} annotation_session_id ID of an annotation session of the volume. If given, only annotations belonging to the annotation session are included in the report. Not available for the iFDO report.
28+
* @apiParam (Optional arguments) {Number[]} only_labels Array of label IDs to restrict the report to. Omit or leave empty to take all labels.
29+
* @apiParam (Optional arguments) {Boolean} aggregate_child_labels If `true`, add the abundance of child labels to the abundance of their parent labels and omit the child labels. This is only valid for the abundance report. Labels that are excluded with `only_labels` are not counted.
30+
* @apiParam (Optional arguments) {Boolean} disable_notifications If `true`, suppress notification to the user on report completion.
31+
* @apiParam (Optional arguments) {Boolean} strip_ifdo If `true`, remove annotation information from the original iFDO file before it is populated with BIIGLE annotations. Only available for the iFDO report.
32+
*
33+
* @apiPermission projectMember
34+
*
35+
* @param StoreVolumeReport $request
36+
* @param int $id Volume ID
37+
*
38+
* @return mixed
39+
*/
40+
public function store(StoreVolumeReport $request, $id)
41+
{
42+
$report = new Report;
43+
$report->source()->associate($request->volume);
44+
$report->type_id = $request->input('type_id');
45+
$report->user()->associate($request->user());
46+
$report->options = $request->getOptions();
47+
$report->save();
48+
49+
$queue = config('reports.generate_report_queue');
50+
GenerateReportJob::dispatch($report)->onQueue($queue);
51+
52+
if ($this->isAutomatedRequest()) {
53+
return $report;
54+
}
55+
}
56+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
namespace Biigle\Http\Controllers\Api\Volumes;
4+
5+
use Biigle\Http\Controllers\Api\Controller;
6+
use Biigle\Volume;
7+
use Exception;
8+
use Illuminate\Http\Request;
9+
use Illuminate\Http\Response;
10+
use Illuminate\Validation\ValidationException;
11+
12+
class ExportAreaController extends Controller
13+
{
14+
/**
15+
* Show the export area of the volume.
16+
*
17+
* @api {get} volumes/:id/export-area Get the export area
18+
* @apiGroup Reports
19+
* @apiName IndexVolumesExportArea
20+
* @apiPermission projectMember
21+
* @apiDescription The export area is a rectangle defined by two points. This endpoint returns an array containing the coordinates as follows: `[x1, y1, x2, y2]`.
22+
* The first point may be any of the 4 points of the rectangle. The second point is the point not directly adjacent to the first. Only available for image volumes.
23+
*
24+
* @apiSuccessExample {json} Success response:
25+
* [100, 100, 1200, 600]
26+
*
27+
* @param int $id Volume ID
28+
* @return array
29+
*/
30+
public function show($id)
31+
{
32+
$volume = Volume::findOrFail($id);
33+
$this->authorize('access', $volume);
34+
35+
if (!$volume->isImageVolume()) {
36+
abort(Response::HTTP_NOT_FOUND);
37+
}
38+
39+
return $volume->exportArea;
40+
}
41+
42+
/**
43+
* Set the export area.
44+
*
45+
* @api {post} volumes/:id/export-area Set the export area
46+
* @apiGroup Volumes
47+
* @apiName StoreVolumesExportArea
48+
* @apiPermission projectAdmin
49+
* @apiDescription Only available for image volumes.
50+
*
51+
* @apiParam (Required arguments) {Number[]} coordinates Coordinates of the export area formatted as `[x1, y1, x2, y2]` array of integers
52+
*
53+
* @param Request $request
54+
* @param int $id Volume ID
55+
*/
56+
public function store(Request $request, $id)
57+
{
58+
$volume = Volume::findOrFail($id);
59+
$this->authorize('update', $volume);
60+
if (!$volume->isImageVolume()) {
61+
throw ValidationException::withMessages(['id' => 'The export area can only be set for image volumes.']);
62+
}
63+
$this->validate($request, ['coordinates' => 'required|array']);
64+
65+
try {
66+
$volume->exportArea = $request->input('coordinates');
67+
$volume->save();
68+
} catch (Exception $e) {
69+
throw ValidationException::withMessages(['coordinates' => $e->getMessage()]);
70+
}
71+
}
72+
73+
/**
74+
* Remove the export area.
75+
*
76+
* @api {delete} volumes/:id/export-area Remove the export area
77+
* @apiGroup Volumes
78+
* @apiName DestroyVolumesExportArea
79+
* @apiPermission projectAdmin
80+
* @apiDescription Only available for image volumes.
81+
*
82+
* @param int $id Volume ID
83+
*/
84+
public function destroy($id)
85+
{
86+
$volume = Volume::findOrFail($id);
87+
$this->authorize('update', $volume);
88+
if (!$volume->isImageVolume()) {
89+
abort(Response::HTTP_NOT_FOUND);
90+
}
91+
$volume->exportArea = null;
92+
$volume->save();
93+
}
94+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace Biigle\Http\Controllers\Views\Projects;
4+
5+
use Biigle\Http\Controllers\Views\Controller;
6+
use Biigle\Modules\MetadataIfdo\IfdoParser;
7+
use Biigle\Project;
8+
use Biigle\ReportType;
9+
use Illuminate\Http\Request;
10+
use Illuminate\Http\Response;
11+
12+
class ProjectReportsController extends Controller
13+
{
14+
/**
15+
* Show the new project reports view.
16+
*
17+
* @param Request $request
18+
* @param int $id
19+
*
20+
* @return \Illuminate\View\View
21+
*/
22+
protected function show(Request $request, $id)
23+
{
24+
$project = Project::findOrFail($id);
25+
$hasVideoVolume = $project->videoVolumes()->exists();
26+
$hasImageVolume = $project->imageVolumes()->exists();
27+
if (!$hasVideoVolume && !$hasImageVolume) {
28+
abort(Response::HTTP_NOT_FOUND);
29+
}
30+
31+
$this->authorize('access', $project);
32+
33+
$userProject = $request->user()->projects()->where('id', $id)->first();
34+
$isMember = $userProject !== null;
35+
$isPinned = $isMember && $userProject->getRelationValue('pivot')->pinned;
36+
$canPin = $isMember && 3 > $request->user()
37+
->projects()
38+
->wherePivot('pinned', true)
39+
->count();
40+
41+
$types = ReportType::when($hasImageVolume, fn ($q) => $q->where('name', 'like', 'Image%'))
42+
->when($hasVideoVolume, fn ($q) => $q->orWhere('name', 'like', 'Video%'))
43+
->orderBy('name', 'asc')
44+
->get();
45+
46+
47+
$hasExportArea = $project->imageVolumes()
48+
->whereNotNull('attrs->export_area')
49+
->exists();
50+
51+
$labelTrees = $project->labelTrees()->with('labels', 'version')->get();
52+
53+
$hasIfdos = false;
54+
55+
foreach ($project->volumes as $volume) {
56+
if ($volume->metadata_parser === IfdoParser::class) {
57+
$hasIfdos = true;
58+
break;
59+
}
60+
}
61+
62+
return view('projects.reports', [
63+
'project' => $project,
64+
'isMember' => $isMember,
65+
'isPinned' => $isPinned,
66+
'canPin' => $canPin,
67+
'activeTab' => 'reports',
68+
'reportTypes' => $types,
69+
'hasExportArea' => $hasExportArea,
70+
'hasImageVolume' => $hasImageVolume,
71+
'hasVideoVolume' => $hasVideoVolume,
72+
'labelTrees' => $labelTrees,
73+
'hasIfdos' => $hasIfdos,
74+
]);
75+
}
76+
}

0 commit comments

Comments
 (0)