|
3029825
|
27810
|
accessibility
|
AXStaticText
|
You cannot create a standard "Storage Pool" You cannot create a standard "Storage Pool" or internal "Volume" over a USB connection....
|
NULL
|
27
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
47
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
0
|
|
3029824
|
27810
|
accessibility
|
AXStaticText
|
However, before we jump into the setup, there is a However, before we jump into the setup, there is an important technical distinction to make regarding how NAS operating systems (including Ugreen's UGOS Pro) handle storage....
|
NULL
|
27
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
46
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
0
|
|
3029823
|
27810
|
accessibility
|
AXStaticText
|
Setting up a 10TB WD Gold on your Ugreen DXP4800 P Setting up a 10TB WD Gold on your Ugreen DXP4800 Plus is a great choice—those enterprise-grade drives are built for heavy workloads....
|
NULL
|
27
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
45
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
0
|
|
3029822
|
27810
|
accessibility
|
AXStaticText
|
Gemini said
|
3029821
|
24
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
44
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
0
|
|
3029821
|
27810
|
accessibility
|
AXHeading
|
Gemini said
|
NULL
|
23
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
43
|
{"help_text":"","role_descript {"help_text":"","role_description":"heading","subrole":"AXUnknown"}...
|
0
|
|
3029820
|
27810
|
accessibility
|
AXStaticText
|
Show thinking
|
NULL
|
28
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
42
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
0
|
|
3029819
|
27810
|
accessibility
|
AXButton
|
Listen
|
NULL
|
24
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
41
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
0
|
|
3029818
|
27810
|
accessibility
|
AXButton
|
Expand
|
NULL
|
21
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
40
|
{"is_enabled":true,"is_focused":fa {"is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
0
|
|
3029817
|
27810
|
accessibility
|
AXStaticText
|
how to create new btrfs storage in ugreen nas dxp4 how to create new btrfs storage in ugreen nas dxp4800 plus from external drive enclosure (10 tb WD gold). How to set it up...
|
NULL
|
23
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
39
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
0
|
|
3029816
|
27810
|
accessibility
|
AXStaticText
|
You said
|
NULL
|
23
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
38
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
0
|
|
3029815
|
27810
|
accessibility
|
AXHeading
|
You said how to create new btrfs storage in ugreen You said how to create new btrfs storage in ugreen nas dxp4800 plus from external drive enclosure (10 tb WD gold). How to set it up...
|
NULL
|
21
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
37
|
{"help_text":"","role_descript {"help_text":"","role_description":"heading","subrole":"AXUnknown"}...
|
0
|
|
3029814
|
27810
|
accessibility
|
AXButton
|
Copy prompt
|
NULL
|
21
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
36
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
0
|
|
3029813
|
27810
|
accessibility
|
AXStaticText
|
Conversation with Gemini
|
3029812
|
16
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
35
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029812
|
27810
|
accessibility
|
AXHeading
|
Conversation with Gemini
|
NULL
|
15
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
34
|
{"help_text":"","role_descript {"help_text":"","role_description":"heading","subrole":"AXUnknown"}...
|
1
|
|
3029811
|
27810
|
accessibility
|
AXButton
|
Open menu for conversation actions.
|
3029810
|
12
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
33
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_expanded":false,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029810
|
27810
|
accessibility
|
AXButton
|
Share conversation
|
NULL
|
11
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
32
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029809
|
27810
|
accessibility
|
AXButton
|
New chat
|
NULL
|
12
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
31
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029808
|
27810
|
accessibility
|
AXButton
|
Main menu
|
NULL
|
12
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
30
|
{"is_enabled":true,"is_focused":fa {"is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029807
|
27810
|
accessibility
|
AXButton
|
Google Account: Lukáš Koválik (kovaliklukas@gmail. Google Account: Lukáš Koválik (kovaliklukas@gmail.com)...
|
NULL
|
12
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
29
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_expanded":false,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029806
|
27810
|
accessibility
|
AXButton
|
Close
|
3029804
|
7
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
28
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029805
|
27810
|
accessibility
|
AXButton
|
AI Chat settings
|
3029804
|
7
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
27
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_expanded":false,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029804
|
27810
|
accessibility
|
AXCheckBox
|
Bitwarden
|
NULL
|
6
|
0.0
|
0.0
|
0.02222222276031971
|
0.035555556416511536
|
NULL
|
26
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"toggle button","subrole":"AXToggle"}...
|
1
|
|
3029803
|
27810
|
accessibility
|
AXCheckBox
|
Open bookmarks (⌘B)
|
NULL
|
6
|
0.0
|
0.0
|
0.02222222276031971
|
0.035555556416511536
|
NULL
|
25
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"toggle button","subrole":"AXToggle"}...
|
1
|
|
3029802
|
27810
|
accessibility
|
AXCheckBox
|
Open history (⇧⌘H)
|
NULL
|
6
|
0.0
|
0.0
|
0.02222222276031971
|
0.035555556416511536
|
NULL
|
24
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"toggle button","subrole":"AXToggle"}...
|
1
|
|
3029801
|
27810
|
accessibility
|
AXCheckBox
|
Close Google Gemini (⌃X)
|
NULL
|
6
|
0.0
|
0.0
|
0.02222222276031971
|
0.035555556416511536
|
NULL
|
23
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"toggle button","subrole":"AXToggle"}...
|
1
|
|
3029800
|
27810
|
accessibility
|
AXCheckBox
|
Customize sidebar
|
NULL
|
6
|
0.0
|
0.0
|
0.02222222276031971
|
0.035555556416511536
|
NULL
|
22
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"toggle button","subrole":"AXToggle"}...
|
1
|
|
3029799
|
27810
|
accessibility
|
AXButton
|
New Tab
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
21
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029798
|
27810
|
accessibility
|
AXStaticText
|
New Tab
|
3029797
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
20
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029797
|
27810
|
accessibility
|
AXRadioButton
|
New Tab
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
19
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029796
|
27810
|
accessibility
|
AXStaticText
|
Manage extra usage for paid Claude plans | Claude Manage extra usage for paid Claude plans | Claude Help Center...
|
3029795
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
18
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029795
|
27810
|
accessibility
|
AXRadioButton
|
Manage extra usage for paid Claude plans | Claude Manage extra usage for paid Claude plans | Claude Help Center...
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
17
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029794
|
27810
|
accessibility
|
AXStaticText
|
Claude
|
3029793
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
16
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029793
|
27810
|
accessibility
|
AXRadioButton
|
Claude
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
15
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029792
|
27810
|
accessibility
|
AXStaticText
|
SQLite Web: db.sqlite
|
3029791
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
14
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029791
|
27810
|
accessibility
|
AXRadioButton
|
SQLite Web: db.sqlite
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
13
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029790
|
27810
|
accessibility
|
AXStaticText
|
SQLite Web: archive.db
|
3029789
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
12
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029789
|
27810
|
accessibility
|
AXRadioButton
|
SQLite Web: archive.db
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
11
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029788
|
27810
|
accessibility
|
AXStaticText
|
Screenpipe — Archive
|
3029787
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
10
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029787
|
27810
|
accessibility
|
AXRadioButton
|
Screenpipe — Archive
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
9
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029786
|
27810
|
accessibility
|
AXStaticText
|
New Tab
|
3029785
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
8
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029785
|
27810
|
accessibility
|
AXRadioButton
|
New Tab
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
7
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029784
|
27810
|
accessibility
|
AXButton
|
Close tab
|
3029782
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
6
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"button","subrole":"AXUnknown"}...
|
1
|
|
3029783
|
27810
|
accessibility
|
AXStaticText
|
DXP4800PLUS-B5F8
|
3029782
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
5
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029782
|
27810
|
accessibility
|
AXRadioButton
|
DXP4800PLUS-B5F8
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
4
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":true,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029781
|
27810
|
accessibility
|
AXStaticText
|
All docs · AFFiNE
|
3029780
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
3
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029780
|
27810
|
accessibility
|
AXRadioButton
|
All docs · AFFiNE
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
2
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029779
|
27810
|
accessibility
|
AXStaticText
|
Screenpipe — Archive
|
3029778
|
5
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
1
|
{"help_text":"","role_descript {"help_text":"","role_description":"text","subrole":"AXUnknown"}...
|
1
|
|
3029778
|
27810
|
accessibility
|
AXRadioButton
|
Screenpipe — Archive
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
0
|
{"help_text":"","is_enabled {"help_text":"","is_enabled":true,"is_focused":false,"is_selected":false,"role_description":"tab","subrole":"AXTabButton"}...
|
1
|
|
3029777
|
27807
|
accessibility
|
AXButton
|
Execute
|
NULL
|
4
|
0.5548537373542786
|
0.07422186434268951
|
0.008643616922199726
|
0.019154030829668045
|
NULL
|
15
|
{"is_enabled":true,"is_expanded":f {"is_enabled":true,"is_expanded":false,"is_focused":false,"is_selected":false,"role_description":"button"}...
|
1
|
|
3029776
|
27807
|
accessibility
|
AXTextArea
|
<?php
declare(strict_types=1);
namespace Jimi <?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\Webhook;
use Carbon\Carbon;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Exceptions\ModelNotFoundException;
use Jiminny\Http\Controllers\AbstractController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Psr\Log\LoggerInterface;
use Throwable;
class ReportController extends AbstractController
{
/**
* Log prefix for all log messages
*/
private const string LOG_PREFIX = '[Report Ready]';
public function __construct(
private readonly AutomatedReportsService $automatedReportsService,
private readonly BusDispatcher $dispatcher,
private readonly LoggerInterface $logger,
private readonly AutomatedReportsCallbackService $callbackService,
private readonly EventDispatcher $eventDispatcher,
) {
}
public function ready(Request $request): JsonResponse
{
$payload = $request->all();
$now = Carbon::now();
$this->logger->info(self::LOG_PREFIX . ' Webhook received', [
'payload' => $payload,
]);
// validate
$reportUuid = $this->callbackService->getResultUuid($payload);
if (empty($reportUuid)) {
return response()->json(['status' => 'error', 'message' => 'Request ID is empty'], status: 400);
}
try {
$report = $this->automatedReportsService->getReportResult($reportUuid);
// validate
if ($this->callbackService->isProcessed($report)) {
$this->logger->warning(self::LOG_PREFIX . ' Report has been already processed', [
'uuid' => $reportUuid,
'currentStatus' => $report->getStatusLabel(),
]);
return response()->json(['status' => 'already_processed']);
}
// always try to get a child podcast cause report configuration cannot be trusted
$reportPodcast = $this->automatedReportsService->findChildResult(
result: $report,
type: AutomatedReportsService::MEDIA_TYPE_PODCAST
);
// update results
$report->update([
'status' => $this->callbackService->getPrimaryStatus($report, $payload),
'response' => $payload,
'generated_at' => $now,
]);
// if a podcast is set, update it
$reportPodcast?->update([
'status' => $this->callbackService->getPodcastStatus($payload),
'response' => $payload,
'generated_at' => $now,
]);
$this->logger->info(self::LOG_PREFIX . ' Report has been processed', [
'uuid' => $reportUuid,
'child_uuid' => $reportPodcast?->getUuid(),
]);
if (! $this->callbackService->isSuccess($payload)) {
$this->logger->warning(self::LOG_PREFIX . ' Error creating report', $payload);
return response()->json(['status' => 'ok']);
}
// If one-off, send the report immediately, if not leave it for the scheduler (automated-reports:send)
if ($report->getReport()->getFrequency() === AutomatedReportsService::FREQUENCY_ONE_OFF) {
// send the primary report
$this->dispatcher->dispatch(new SendReportJob($reportUuid));
// send the podcast report if it set and generated
if ($reportPodcast && $reportPodcast->getStatus() === AutomatedReportResult::STATUS_GENERATED) {
$this->dispatcher->dispatch(new SendReportJob(reportUuid: $reportPodcast->getUuid()));
}
}
// Track Datadog metrics for automated reports
$automatedReport = $report->getReport();
$this->callbackService->pushToDatadog($automatedReport, $report);
if ($reportPodcast) {
$this->callbackService->pushToDatadog($automatedReport, $reportPodcast);
}
$this->logger->info(self::LOG_PREFIX . ' Triggering Event for UserPilot tracking', [
'report_uuid' => $automatedReport->getUuid(),
'result_uuid' => $reportUuid,
]);
$this->eventDispatcher->dispatch(new AutomatedReportGenerated($automatedReport));
} catch (ModelNotFoundException $exception) {
$this->logger->error(self::LOG_PREFIX . ' Report not found', [
'uuid' => $reportUuid,
'error' => $exception->getMessage(),
]);
return response()->json(['status' => 'error', 'message' => 'Report not found'], status: 404);
} catch (Throwable $exception) {
$this->logger->error(self::LOG_PREFIX . ' Failed to update report status', [
'uuid' => $reportUuid,
'error' => $exception->getMessage(),
]);
return response()->json(['status' => 'error', 'message' => 'Failed to update report status'], status: 500);
}
return response()->json(['status' => 'ok']);
}
}...
|
NULL
|
4
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
14
|
{"is_enabled":true,"is_expanded":f {"is_enabled":true,"is_expanded":false,"is_focused":true,"is_selected":false,"role_description":"text entry area","value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\Webhook;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Contracts\\Bus\\Dispatcher as BusDispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Jiminny\\Http\\Controllers\\AbstractController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Psr\\Log\\LoggerInterface;\nuse Throwable;\n\nclass ReportController extends AbstractController\n{\n /**\n * Log prefix for all log messages\n */\n private const string LOG_PREFIX = '[Report Ready]';\n\n public function __construct(\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly BusDispatcher $dispatcher,\n private readonly LoggerInterface $logger,\n private readonly AutomatedReportsCallbackService $callbackService,\n private readonly EventDispatcher $eventDispatcher,\n ) {\n }\n\n public function ready(Request $request): JsonResponse\n {\n $payload = $request->all();\n $now = Carbon::now();\n\n $this->logger->info(self::LOG_PREFIX . ' Webhook received', [\n 'payload' => $payload,\n ]);\n\n // validate\n $reportUuid = $this->callbackService->getResultUuid($payload);\n if (empty($reportUuid)) {\n return response()->json(['status' => 'error', 'message' => 'Request ID is empty'], status: 400);\n }\n\n try {\n $report = $this->automatedReportsService->getReportResult($reportUuid);\n\n // validate\n if ($this->callbackService->isProcessed($report)) {\n $this->logger->warning(self::LOG_PREFIX . ' Report has been already processed', [\n 'uuid' => $reportUuid,\n 'currentStatus' => $report->getStatusLabel(),\n ]);\n\n return response()->json(['status' => 'already_processed']);\n }\n\n // always try to get a child podcast cause report configuration cannot be trusted\n $reportPodcast = $this->automatedReportsService->findChildResult(\n result: $report,\n type: AutomatedReportsService::MEDIA_TYPE_PODCAST\n );\n\n // update results\n $report->update([\n 'status' => $this->callbackService->getPrimaryStatus($report, $payload),\n 'response' => $payload,\n 'generated_at' => $now,\n ]);\n // if a podcast is set, update it\n $reportPodcast?->update([\n 'status' => $this->callbackService->getPodcastStatus($payload),\n 'response' => $payload,\n 'generated_at' => $now,\n ]);\n\n $this->logger->info(self::LOG_PREFIX . ' Report has been processed', [\n 'uuid' => $reportUuid,\n 'child_uuid' => $reportPodcast?->getUuid(),\n ]);\n\n if (! $this->callbackService->isSuccess($payload)) {\n $this->logger->warning(self::LOG_PREFIX . ' Error creating report', $payload);\n\n return response()->json(['status' => 'ok']);\n }\n\n // If one-off, send the report immediately, if not leave it for the scheduler (automated-reports:send)\n if ($report->getReport()->getFrequency() === AutomatedReportsService::FREQUENCY_ONE_OFF) {\n // send the primary report\n $this->dispatcher->dispatch(new SendReportJob($reportUuid));\n\n // send the podcast report if it set and generated\n if ($reportPodcast && $reportPodcast->getStatus() === AutomatedReportResult::STATUS_GENERATED) {\n $this->dispatcher->dispatch(new SendReportJob(reportUuid: $reportPodcast->getUuid()));\n }\n }\n\n // Track Datadog metrics for automated reports\n $automatedReport = $report->getReport();\n $this->callbackService->pushToDatadog($automatedReport, $report);\n\n if ($reportPodcast) {\n $this->callbackService->pushToDatadog($automatedReport, $reportPodcast);\n }\n\n $this->logger->info(self::LOG_PREFIX . ' Triggering Event for UserPilot tracking', [\n 'report_uuid' => $automatedReport->getUuid(),\n 'result_uuid' => $reportUuid,\n ]);\n $this->eventDispatcher->dispatch(new AutomatedReportGenerated($automatedReport));\n } catch (ModelNotFoundException $exception) {\n $this->logger->error(self::LOG_PREFIX . ' Report not found', [\n 'uuid' => $reportUuid,\n 'error' => $exception->getMessage(),\n ]);\n\n return response()->json(['status' => 'error', 'message' => 'Report not found'], status: 404);\n } catch (Throwable $exception) {\n $this->logger->error(self::LOG_PREFIX . ' Failed to update report status', [\n 'uuid' => $reportUuid,\n 'error' => $exception->getMessage(),\n ]);\n\n return response()->json(['status' => 'error', 'message' => 'Failed to update report status'], status: 500);\n }\n\n return response()->json(['status' => 'ok']);\n }\n}"}...
|
1
|