-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1028 from biigle/merge-reports-module
Merge reports module
- Loading branch information
Showing
170 changed files
with
19,182 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php | ||
|
||
namespace Biigle\Http\Controllers\Api; | ||
|
||
use Biigle\Http\Requests\StoreProjectReport; | ||
use Biigle\Jobs\GenerateReportJob; | ||
use Biigle\Report; | ||
|
||
class ProjectReportController extends Controller | ||
{ | ||
/** | ||
* Generate a project report. | ||
* | ||
* @api {post} projects/:id/reports Request a project report | ||
* @apiGroup Reports | ||
* @apiName GenerateProjectReport | ||
* | ||
* @apiParam {Number} id The project ID. | ||
* | ||
* @apiParam (Required arguments) {Number} type_id The report type ID. | ||
* | ||
* @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. | ||
* @apiParam (Optional arguments) {Boolean} newest_label If `true`, restrict the report to the newest label of each annotation. | ||
* @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. | ||
* @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. | ||
* @apiParam (Optional arguments) {Number[]} only_labels Array of label IDs to restrict the report to. Omit or leave empty to take all labels. | ||
* @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. | ||
* @apiParam (Optional arguments) {Boolean} disable_notifications If `true`, suppress notification to the user on report completion. | ||
* @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. | ||
* | ||
* @apiPermission projectMember | ||
* | ||
* @param StoreProjectReport $request | ||
* @param int $id Project ID | ||
* | ||
* @return mixed | ||
*/ | ||
public function store(StoreProjectReport $request, $id) | ||
{ | ||
$report = new Report; | ||
$report->source()->associate($request->project); | ||
$report->type_id = $request->input('type_id'); | ||
$report->user()->associate($request->user()); | ||
$report->options = $request->getOptions(); | ||
$report->save(); | ||
|
||
$queue = config('reports.generate_report_queue'); | ||
GenerateReportJob::dispatch($report)->onQueue($queue); | ||
|
||
if ($this->isAutomatedRequest()) { | ||
return $report; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<?php | ||
|
||
namespace Biigle\Http\Controllers\Api; | ||
|
||
use Biigle\Report; | ||
use Illuminate\Http\Response; | ||
use Storage; | ||
|
||
class ReportsController extends Controller | ||
{ | ||
/** | ||
* @apiDefine reportOwner Report Owner | ||
* The user must be the owner of the report. | ||
*/ | ||
|
||
/** | ||
* Shows the specified report file. | ||
* | ||
* @api {get} reports/:id Get a report file | ||
* @apiGroup Reports | ||
* @apiName ShowReport | ||
* @apiPermission reportOwner | ||
* @apiDescription Responds with the file. | ||
* | ||
* @apiParam {Number} id The report ID. | ||
* | ||
* @param int $id report id | ||
* @return mixed | ||
*/ | ||
public function show($id) | ||
{ | ||
$report = Report::findOrFail($id); | ||
$this->authorize('access', $report); | ||
$report->touch(); | ||
|
||
$disk = Storage::disk(config('reports.storage_disk')); | ||
|
||
if (!$disk->exists($report->getStorageFilename())) { | ||
abort(Response::HTTP_NOT_FOUND); | ||
} | ||
|
||
$path = $report->getStorageFilename(); | ||
return $disk->download($path, $report->filename) | ||
// Use a custom fallback with fread() because the default fpassthru() could | ||
// lead to an out of memory error with large reports. | ||
->setCallback(function () use ($disk, $path) { | ||
$stream = $disk->readStream($path); | ||
while (!feof($stream)) { | ||
echo fread($stream, 8192); | ||
} | ||
fclose($stream); | ||
}); | ||
} | ||
|
||
/** | ||
* Delete a report. | ||
* | ||
* @api {delete} reports/:id Delete a report | ||
* @apiGroup Reports | ||
* @apiName DestroyReport | ||
* @apiPermission reportOwner | ||
* | ||
* @apiParam {Number} id The report ID. | ||
* | ||
* @param int $id report id | ||
* @return mixed | ||
*/ | ||
public function destroy($id) | ||
{ | ||
$report = Report::findOrFail($id); | ||
$this->authorize('destroy', $report); | ||
$report->delete(); | ||
|
||
if (!$this->isAutomatedRequest()) { | ||
return $this->fuzzyRedirect() | ||
->with('message', 'Report deleted.') | ||
->with('messageType', 'success'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
namespace Biigle\Http\Controllers\Api; | ||
|
||
use Biigle\Http\Requests\StoreVolumeReport; | ||
use Biigle\Jobs\GenerateReportJob; | ||
use Biigle\Report; | ||
|
||
class VolumeReportController extends Controller | ||
{ | ||
/** | ||
* Generate a volume report. | ||
* | ||
* @api {post} volumes/:id/reports Request a volume report | ||
* @apiGroup Reports | ||
* @apiName GenerateVolumeReport | ||
* @apiDescription Accepts only requests for annotation and image label reports. | ||
* | ||
* @apiParam {Number} id The volume ID. | ||
* | ||
* @apiParam (Required arguments) {Number} type_id The report type ID. | ||
* | ||
* @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. | ||
* @apiParam (Optional arguments) {Boolean} newest_label If `true`, restrict the report to the newest label of each annotation. | ||
* @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. | ||
* @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. | ||
* @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. | ||
* @apiParam (Optional arguments) {Number[]} only_labels Array of label IDs to restrict the report to. Omit or leave empty to take all labels. | ||
* @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. | ||
* @apiParam (Optional arguments) {Boolean} disable_notifications If `true`, suppress notification to the user on report completion. | ||
* @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. | ||
* | ||
* @apiPermission projectMember | ||
* | ||
* @param StoreVolumeReport $request | ||
* @param int $id Volume ID | ||
* | ||
* @return mixed | ||
*/ | ||
public function store(StoreVolumeReport $request, $id) | ||
{ | ||
$report = new Report; | ||
$report->source()->associate($request->volume); | ||
$report->type_id = $request->input('type_id'); | ||
$report->user()->associate($request->user()); | ||
$report->options = $request->getOptions(); | ||
$report->save(); | ||
|
||
$queue = config('reports.generate_report_queue'); | ||
GenerateReportJob::dispatch($report)->onQueue($queue); | ||
|
||
if ($this->isAutomatedRequest()) { | ||
return $report; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
<?php | ||
|
||
namespace Biigle\Http\Controllers\Api\Volumes; | ||
|
||
use Biigle\Http\Controllers\Api\Controller; | ||
use Biigle\Volume; | ||
use Exception; | ||
use Illuminate\Http\Request; | ||
use Illuminate\Http\Response; | ||
use Illuminate\Validation\ValidationException; | ||
|
||
class ExportAreaController extends Controller | ||
{ | ||
/** | ||
* Show the export area of the volume. | ||
* | ||
* @api {get} volumes/:id/export-area Get the export area | ||
* @apiGroup Reports | ||
* @apiName IndexVolumesExportArea | ||
* @apiPermission projectMember | ||
* @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]`. | ||
* 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. | ||
* | ||
* @apiSuccessExample {json} Success response: | ||
* [100, 100, 1200, 600] | ||
* | ||
* @param int $id Volume ID | ||
* @return array | ||
*/ | ||
public function show($id) | ||
{ | ||
$volume = Volume::findOrFail($id); | ||
$this->authorize('access', $volume); | ||
|
||
if (!$volume->isImageVolume()) { | ||
abort(Response::HTTP_NOT_FOUND); | ||
} | ||
|
||
return $volume->exportArea; | ||
} | ||
|
||
/** | ||
* Set the export area. | ||
* | ||
* @api {post} volumes/:id/export-area Set the export area | ||
* @apiGroup Volumes | ||
* @apiName StoreVolumesExportArea | ||
* @apiPermission projectAdmin | ||
* @apiDescription Only available for image volumes. | ||
* | ||
* @apiParam (Required arguments) {Number[]} coordinates Coordinates of the export area formatted as `[x1, y1, x2, y2]` array of integers | ||
* | ||
* @param Request $request | ||
* @param int $id Volume ID | ||
*/ | ||
public function store(Request $request, $id) | ||
{ | ||
$volume = Volume::findOrFail($id); | ||
$this->authorize('update', $volume); | ||
if (!$volume->isImageVolume()) { | ||
throw ValidationException::withMessages(['id' => 'The export area can only be set for image volumes.']); | ||
} | ||
$this->validate($request, ['coordinates' => 'required|array']); | ||
|
||
try { | ||
$volume->exportArea = $request->input('coordinates'); | ||
$volume->save(); | ||
} catch (Exception $e) { | ||
throw ValidationException::withMessages(['coordinates' => $e->getMessage()]); | ||
} | ||
} | ||
|
||
/** | ||
* Remove the export area. | ||
* | ||
* @api {delete} volumes/:id/export-area Remove the export area | ||
* @apiGroup Volumes | ||
* @apiName DestroyVolumesExportArea | ||
* @apiPermission projectAdmin | ||
* @apiDescription Only available for image volumes. | ||
* | ||
* @param int $id Volume ID | ||
*/ | ||
public function destroy($id) | ||
{ | ||
$volume = Volume::findOrFail($id); | ||
$this->authorize('update', $volume); | ||
if (!$volume->isImageVolume()) { | ||
abort(Response::HTTP_NOT_FOUND); | ||
} | ||
$volume->exportArea = null; | ||
$volume->save(); | ||
} | ||
} |
76 changes: 76 additions & 0 deletions
76
app/Http/Controllers/Views/Projects/ProjectReportsController.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<?php | ||
|
||
namespace Biigle\Http\Controllers\Views\Projects; | ||
|
||
use Biigle\Http\Controllers\Views\Controller; | ||
use Biigle\Modules\MetadataIfdo\IfdoParser; | ||
use Biigle\Project; | ||
use Biigle\ReportType; | ||
use Illuminate\Http\Request; | ||
use Illuminate\Http\Response; | ||
|
||
class ProjectReportsController extends Controller | ||
{ | ||
/** | ||
* Show the new project reports view. | ||
* | ||
* @param Request $request | ||
* @param int $id | ||
* | ||
* @return \Illuminate\View\View | ||
*/ | ||
protected function show(Request $request, $id) | ||
{ | ||
$project = Project::findOrFail($id); | ||
$hasVideoVolume = $project->videoVolumes()->exists(); | ||
$hasImageVolume = $project->imageVolumes()->exists(); | ||
if (!$hasVideoVolume && !$hasImageVolume) { | ||
abort(Response::HTTP_NOT_FOUND); | ||
} | ||
|
||
$this->authorize('access', $project); | ||
|
||
$userProject = $request->user()->projects()->where('id', $id)->first(); | ||
$isMember = $userProject !== null; | ||
$isPinned = $isMember && $userProject->getRelationValue('pivot')->pinned; | ||
$canPin = $isMember && 3 > $request->user() | ||
->projects() | ||
->wherePivot('pinned', true) | ||
->count(); | ||
|
||
$types = ReportType::when($hasImageVolume, fn ($q) => $q->where('name', 'like', 'Image%')) | ||
->when($hasVideoVolume, fn ($q) => $q->orWhere('name', 'like', 'Video%')) | ||
->orderBy('name', 'asc') | ||
->get(); | ||
|
||
|
||
$hasExportArea = $project->imageVolumes() | ||
->whereNotNull('attrs->export_area') | ||
->exists(); | ||
|
||
$labelTrees = $project->labelTrees()->with('labels', 'version')->get(); | ||
|
||
$hasIfdos = false; | ||
|
||
foreach ($project->volumes as $volume) { | ||
if ($volume->metadata_parser === IfdoParser::class) { | ||
$hasIfdos = true; | ||
break; | ||
} | ||
} | ||
|
||
return view('projects.reports', [ | ||
'project' => $project, | ||
'isMember' => $isMember, | ||
'isPinned' => $isPinned, | ||
'canPin' => $canPin, | ||
'activeTab' => 'reports', | ||
'reportTypes' => $types, | ||
'hasExportArea' => $hasExportArea, | ||
'hasImageVolume' => $hasImageVolume, | ||
'hasVideoVolume' => $hasVideoVolume, | ||
'labelTrees' => $labelTrees, | ||
'hasIfdos' => $hasIfdos, | ||
]); | ||
} | ||
} |
Oops, something went wrong.