From 125bd18e19ab50a60f25306b522231d7426f2d91 Mon Sep 17 00:00:00 2001 From: Matthias Guillitte Date: Thu, 23 Oct 2025 19:01:37 +0200 Subject: [PATCH] Added Eldoradu Robux Price Sentry Job --- .../EldoradoRobuxPriceSentryJob.php | 124 ++++++++++++++++++ ...00_add_eldorado_robux_price_sentry_job.php | 59 +++++++++ .../js/Components/Layout/Job/JobForm.vue | 2 +- .../js/Components/Layout/Job/JobFormField.vue | 3 +- routes/console.php | 3 + 5 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 app/Browser/Jobs/EldoradoRobuxPriceSentry/EldoradoRobuxPriceSentryJob.php create mode 100644 database/migrations/2025_10_23_155000_add_eldorado_robux_price_sentry_job.php diff --git a/app/Browser/Jobs/EldoradoRobuxPriceSentry/EldoradoRobuxPriceSentryJob.php b/app/Browser/Jobs/EldoradoRobuxPriceSentry/EldoradoRobuxPriceSentryJob.php new file mode 100644 index 0000000..1ba8e67 --- /dev/null +++ b/app/Browser/Jobs/EldoradoRobuxPriceSentry/EldoradoRobuxPriceSentryJob.php @@ -0,0 +1,124 @@ +downloadFolder = base_path($this->downloadFolder); + } + + public function run(Browser $browser): ?JobRun + { + $startTime = microtime(true); + + Log::info("Running EldoradoRobuxPriceSentryJob"); + $this->jobInfos = Job::find($this->jobId)->jobInfosTable(); + $this->jobRun = new JobRun([ + "job_id" => $this->jobId, + "success" => false, + ]); + $this->jobRun->save(); + + dump("visiting " . microtime(true) - $startTime); + $browser->visit(self::LINK); + sleep(5); + $this->sendPrices($browser); + + $this->jobRun->success = true; + $this->jobRun->save(); + + Log::info("EldoradoRobuxPriceSentryJob run ended"); + + return $this->jobRun; + } + + /** + * @inheritDoc + */ + public function runTest(Browser $browser): ?JobRun + { + $this->jobInfos = Job::find($this->jobId)->jobInfosTable(); + try { + $browser->visit(self::LINK); + sleep(5); + + return $this->makeSimpleJobRun( + true, + "Test réussi", + "Datboi a réussi à charger la page Eldorado." + ); + } catch (\Exception $e) { + return $this->makeSimpleJobRun( + false, + "Test échoué", + "Datboi n'a pas réussi à charger la page Eldorado :\n" . $e->getMessage() + ); + } + } + + private function sendPrices(Browser $browser): void + { + $lowestPriceElement = $browser->driver->findElement(WebDriverBy::xpath('(//eld-offer-price)[2]/strong')); + $lowestPriceText = $lowestPriceElement->getText(); // Ex: " 0,00478 € " + $lowestPrice = (float)str_replace(["€", ","], ["", "."], trim($lowestPriceText)); + + $threshold = floatval(str_replace(",", ".", $this->jobInfos->get("eldorado_robux_price_threshold"))); + dump($threshold); + + Log::info("EldoradoRobuxPriceSentryJob: lowest price = $lowestPrice €, threshold = $threshold €"); + + if ($lowestPrice <= $threshold) { + $message = "Le prix des Robux sur Eldorado est actuellement de **" . number_format($lowestPrice, 5, ",", " ") . " €**/Robux, ce qui est inférieur ou égal au seuil de **" . number_format($threshold, 5, ",", " ") . " €**.\n\n[Voir l'offre sur Eldorado]( " . self::LINK . " )"; + $options = []; + + if ($this->jobInfos->get("eldorado_robux_price_discord_webhook") !== null) { // Custom discord webhook + $options["discord_webhook_url"] = $this->jobInfos->get("eldorado_robux_price_discord_webhook"); + } + + AllNotification::send( + new SimpleNotification( + $this->jobId, + "Alerte Robux Eldorado 🤑", + $message + ), + $options + ); + + Log::info("EldoradoRobuxPriceSentryJob: alert sent"); + } else { + Log::info("EldoradoRobuxPriceSentryJob: no alert sent"); + } + } +} diff --git a/database/migrations/2025_10_23_155000_add_eldorado_robux_price_sentry_job.php b/database/migrations/2025_10_23_155000_add_eldorado_robux_price_sentry_job.php new file mode 100644 index 0000000..4511a76 --- /dev/null +++ b/database/migrations/2025_10_23_155000_add_eldorado_robux_price_sentry_job.php @@ -0,0 +1,59 @@ + $newJobId, + "name" => "Eldorado Robux Price Sentry", + "description" => "Surveille les prix des Robux sur Eldorado.", + ]); + + $decimalType = JobInfoType::create([ + "name" => "decimal", + ]); + + JobInfo::forceCreate([ + "key" => "eldorado_robux_price_threshold", + "name" => "Seuil de prix des Robux", + "description" => "Le seuil de prix par robux en euros pour déclencher une alerte.", + "placeholder" => "0,00350", + "is_required" => true, + "job_info_type_id" => $decimalType->id, + "job_id" => $newJobId, + ]); + + JobInfo::forceCreate([ + "key" => "eldorado_robux_price_discord_webhook", + "name" => "Webhook Discord pour les alertes de prix des Robux", + "description" => "L'URL du webhook Discord pour recevoir les alertes de prix des Robux.", + "placeholder" => "https://discord.com/api/webhooks/...", + "is_required" => false, + "job_info_type_id" => 4, + "job_id" => $newJobId, + ]); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Job::where("id", 5)->delete(); + JobInfo::where("job_id", 5)->delete(); + } +}; diff --git a/resources/js/Components/Layout/Job/JobForm.vue b/resources/js/Components/Layout/Job/JobForm.vue index d70eb46..701f8f0 100644 --- a/resources/js/Components/Layout/Job/JobForm.vue +++ b/resources/js/Components/Layout/Job/JobForm.vue @@ -47,7 +47,7 @@ const isActiveJobInfo = ref({ description: "Activer le job", value: props.job.is_active, is_required: false, - job_info_type: { name: "checkbox" } as JobInfoType, + job_info_type: { name: "boolean" } as JobInfoType, } as JobInfo); async function testJob() { diff --git a/resources/js/Components/Layout/Job/JobFormField.vue b/resources/js/Components/Layout/Job/JobFormField.vue index 03b2982..ed4d28f 100644 --- a/resources/js/Components/Layout/Job/JobFormField.vue +++ b/resources/js/Components/Layout/Job/JobFormField.vue @@ -19,7 +19,8 @@ const jobInfoType = props.jobInfo.job_info_type.name; {{ jobInfo.description }} - + + diff --git a/routes/console.php b/routes/console.php index 156ffb0..ca42b14 100644 --- a/routes/console.php +++ b/routes/console.php @@ -1,5 +1,6 @@ daily()->onOneServer()->withoutOverlapping()->na Schedule::job(new HellcaseBattlesJob)->hourly()->onOneServer()->withoutOverlapping()->name('hellcase_battles')->description('Hellcase battles job'); Schedule::job(new InstagramRepostJob)->everyThreeHours()->onOneServer()->withoutOverlapping()->name('instagram_reposts')->description('Instagram reposts job'); Schedule::job(new InstagramNotificationHandlingJob)->hourly()->onOneServer()->withoutOverlapping()->name('instagram_reposts_notifications')->description('Instagram reposts notification handling job'); +Schedule::job(new EldoradoRobuxPriceSentryJob)->dailyAt("14:00")->onOneServer()->withoutOverlapping()->name('eldorado_robux_price_sentry')->description('Eldorado Robux Price Sentry job'); +