From b1f38da9b576f42a21c9950a1b3f3bd362cf7858 Mon Sep 17 00:00:00 2001 From: Vahn Gomes Date: Fri, 21 Jul 2023 14:27:32 -0400 Subject: [PATCH 1/5] Update build tag in .woodpecker.yml for tag events --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 8817713..4dd8b8c 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -29,7 +29,7 @@ pipeline: repo: insidiousfiddler/redbeards-atis-generator dockerfile: Dockerfile platforms: *platforms - tag: [latest, "${CI_COMMIT_TAG#v}"] + tag: [latest, "${CI_COMMIT_TAG}"] when: event: tag From e33b5cea84f22a8809f4b19cf929c1bb2559f872 Mon Sep 17 00:00:00 2001 From: Vahn Gomes Date: Fri, 21 Jul 2023 16:35:38 -0400 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=94=A7=20chore(app.php):=20add=20'ver?= =?UTF-8?q?sion'=20configuration=20option=20to=20store=20the=20application?= =?UTF-8?q?=20version=20=F0=9F=94=A7=20chore(openapi.php):=20use=20the=20'?= =?UTF-8?q?version'=20configuration=20option=20from=20app.php=20to=20set?= =?UTF-8?q?=20the=20OpenAPI=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/app.php | 12 ++++++++++++ src/config/openapi.php | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/config/app.php b/src/config/app.php index 468c144..1abde6b 100644 --- a/src/config/app.php +++ b/src/config/app.php @@ -32,6 +32,18 @@ 'env' => env('APP_ENV', 'production'), + /* + |-------------------------------------------------------------------------- + | Application Version + |-------------------------------------------------------------------------- + | + | This value is the version of your application. This value is used when the + | framework needs to place the application's version in a notification or + | any other location as required by the application or its packages. + | + */ + 'version' => \Tremby\LaravelGitVersion\GitVersionHelper::getVersion() ?? 'dev', + /* |-------------------------------------------------------------------------- | Application Debug Mode diff --git a/src/config/openapi.php b/src/config/openapi.php index 7d09447..8891b17 100644 --- a/src/config/openapi.php +++ b/src/config/openapi.php @@ -9,7 +9,7 @@ 'info' => [ 'title' => "Redbeard's ATIS Generator", 'description' => 'A simple to use tool for non VATSIM/IVAO/PilotEdge controllers to generate an ATIS in text and spoken formats.', - 'version' => '2.0.0-beta', + 'version' => config('app.version'), 'contact' => [ 'name' => 'Atis Support', 'email' => 'atis@vahngomes.dev', From d31c99ac1e9366049bf8a8c840c5beadc9a1bde2 Mon Sep 17 00:00:00 2001 From: Vahn Gomes Date: Fri, 21 Jul 2023 16:36:15 -0400 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=90=9B=20fix(TextToSpeechController.p?= =?UTF-8?q?hp):=20fix=20incorrect=20parameter=20name=20in=20index=20method?= =?UTF-8?q?=20=E2=9C=A8=20feat(TextToSpeechController.php):=20add=20suppor?= =?UTF-8?q?t=20for=20retrieving=20ATIS=20audio=20file=20by=20ID=20and=20IC?= =?UTF-8?q?AO=20code=20in=20index=20method=20=F0=9F=94=A7=20chore(TextToSp?= =?UTF-8?q?eechController.php):=20refactor=20generate=20method=20to=20use?= =?UTF-8?q?=20request=20parameters=20instead=20of=20method=20parameters=20?= =?UTF-8?q?=F0=9F=94=A7=20chore(TextToSpeechController.php):=20refactor=20?= =?UTF-8?q?delete=20method=20to=20remove=20unused=20parameter=20=E2=9C=A8?= =?UTF-8?q?=20feat(GetTextToSpeechParameters.php):=20add=20GetTextToSpeech?= =?UTF-8?q?Parameters=20class=20to=20handle=20query=20parameters=20for=20r?= =?UTF-8?q?etrieving=20ATIS=20audio=20file=20=E2=9C=A8=20feat(GetTextToSpe?= =?UTF-8?q?echRequestBody.php):=20add=20GetTextToSpeechRequestBody=20class?= =?UTF-8?q?=20to=20handle=20request=20body=20for=20retrieving=20ATIS=20aud?= =?UTF-8?q?io=20file=20=E2=9C=A8=20feat(ErrorGetTextToSpeechResponse.php):?= =?UTF-8?q?=20add=20ErrorGetTextToSpeechResponse=20class=20to=20handle=20e?= =?UTF-8?q?rror=20response=20for=20retrieving=20ATIS=20audio=20file=20?= =?UTF-8?q?=E2=9C=A8=20feat(SuccessResponse.php):=20add=20SuccessResponse?= =?UTF-8?q?=20class=20to=20handle=20success=20response=20for=20retrieving?= =?UTF-8?q?=20ATIS=20audio=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐛 fix(redbeard.js): add missing semicolons to improve code readability and prevent potential issues ✨ feat(redbeard.js): refactor API routes to use a prefix for better organization and readability ✨ feat(redbeard.js): add support for generating ATIS audio file using Text-to-Speech (TTS) functionality ✨ feat(redbeard.js): add support for deleting ATIS audio file generated using TTS functionality --- .../API/TextToSpeechController.php | 69 ++++++++-- .../Parameters/GetTextToSpeechParameters.php | 33 +++++ .../TTS/GetTextToSpeechRequestBody.php | 31 +++++ .../ErrorGetTextToSpeechResponse.php | 26 ++++ .../TTS/GetTextToSpeech/SuccessResponse.php | 33 +++++ src/public/lib/js/redbeard.js | 128 +++++++++++------- src/routes/api.php | 9 +- 7 files changed, 264 insertions(+), 65 deletions(-) create mode 100644 src/app/OpenApi/Parameters/GetTextToSpeechParameters.php create mode 100644 src/app/OpenApi/RequestBodies/TTS/GetTextToSpeechRequestBody.php create mode 100644 src/app/OpenApi/Responses/TTS/GetTextToSpeech/ErrorGetTextToSpeechResponse.php create mode 100644 src/app/OpenApi/Responses/TTS/GetTextToSpeech/SuccessResponse.php diff --git a/src/app/Http/Controllers/API/TextToSpeechController.php b/src/app/Http/Controllers/API/TextToSpeechController.php index 7e88c9a..0a389e5 100644 --- a/src/app/Http/Controllers/API/TextToSpeechController.php +++ b/src/app/Http/Controllers/API/TextToSpeechController.php @@ -6,12 +6,16 @@ use App\Http\Controllers\Controller; use App\Models\ATISAudioFile; use App\OpenApi\Parameters\GetAirportParameters; +use App\OpenApi\Parameters\GetTextToSpeechParameters; use App\OpenApi\RequestBodies\TTS\GenerateRequestBody; +use App\OpenApi\RequestBodies\TTS\GetTextToSpeechRequestBody; use App\OpenApi\Responses\TTS\ErrorGeneratingResponse; use App\OpenApi\Responses\TTS\ErrorRequestConflictResponse; use App\OpenApi\Responses\TTS\ErrorValidatingIcaoResponse; use App\OpenApi\Responses\TTS\ErrorWithVoiceAPIResponse; use App\OpenApi\Responses\TTS\SuccessResponse; +use App\OpenApi\Responses\TTS\GetTextToSpeech\ErrorGetTextToSpeechResponse; +use App\OpenApi\Responses\TTS\GetTextToSpeech\SuccessResponse as GetTextToSpeechSuccessResponse; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; @@ -25,15 +29,58 @@ class TextToSpeechController extends Controller * * Gets a link to a mp3 text-to-speech file for an airport and returns it in a JSON response. * - * @param string $icao The ICAO code of the airport to generate the TTS for. * @param Request $request - * @return void + * @return JsonResponse */ #[OpenApi\Operation(tags: ['Text to Speech'])] - #[OpenApi\Parameters(factory: GetAirportParameters::class)] - public function index(string $icao, Request $request): void + #[OpenApi\Parameters(factory: GetTextToSpeechParameters::class)] + #[OpenApi\Response(factory: ErrorValidatingIcaoResponse::class, statusCode: 400)] + #[OpenApi\Response(factory: ErrorGetTextToSpeechResponse::class, statusCode: 404)] + #[OpenApi\Response(factory: GetTextToSpeechSuccessResponse::class, statusCode: 200)] + public function index(Request $request): JsonResponse { - // TODO: Get mp3 atis file and return link and id. + // Get the request parameters + $id = $request->id; + $icao = $request->icao; + + // Validate the request + if ( + !isset($icao) || + !Helpers::validateIcao($icao) + ) { + return response()->json([ + 'status' => 'error', + 'message' => 'Invalid ICAO code.', + 'code' => 400, + 'data' => null + ]); + } + + // Get the ATIS audio file + $atis_file = ATISAudioFile::where('icao', $icao)->where('id', $id)->first(); + + // Check if the ATIS audio file exists + if ($atis_file == null || !$atis_file->exists()) { + return response()->json([ + 'status' => 'error', + 'message' => 'ATIS audio file not found.', + 'code' => 404, + 'data' => null + ]); + } + + // Return the response + return response()->json([ + 'status' => 'success', + 'message' => 'ATIS audio file found.', + 'code' => 200, + 'data' => [ + 'id' => $atis_file->id, + 'name' => $atis_file->file_name, + 'url' => $atis_file->url, + 'expires_at' => $atis_file->expires_at, + ] + ]); } /** @@ -53,8 +100,13 @@ public function index(string $icao, Request $request): void #[OpenApi\Response(factory: ErrorWithVoiceAPIResponse::class, statusCode: 500)] #[OpenApi\Response(factory: ErrorGeneratingResponse::class, statusCode: 422)] #[OpenApi\Response(factory: SuccessResponse::class, statusCode: 200)] - public function generate(string $icao, Request $request): JsonResponse + public function generate(Request $request): JsonResponse { + // Get the request parameters + $icao = $request->icao; + $atis = $request->atis; + $ident = $request->ident; + // Validate the request if (!Helpers::validateIcao($icao)) { return response()->json([ @@ -65,9 +117,6 @@ public function generate(string $icao, Request $request): JsonResponse ]); } - $atis = $request->atis; - $ident = $request->ident; - // Check if the request has the required parameters, not using request()->validate() for now. if (!isset($atis) || !isset($ident) || !isset($icao)) { return response()->json([ @@ -201,7 +250,7 @@ public function generate(string $icao, Request $request): JsonResponse */ #[OpenApi\Operation(tags: ['Text to Speech'])] #[OpenApi\Parameters(factory: GetAirportParameters::class)] - public function delete(string $icao, Request $request): void + public function delete(Request $request): void { // TODO: Delete mp3 atis file. } diff --git a/src/app/OpenApi/Parameters/GetTextToSpeechParameters.php b/src/app/OpenApi/Parameters/GetTextToSpeechParameters.php new file mode 100644 index 0000000..044071e --- /dev/null +++ b/src/app/OpenApi/Parameters/GetTextToSpeechParameters.php @@ -0,0 +1,33 @@ +name('icao') + ->description('ICAO code of the airport') + ->required(true) + ->schema(Schema::string()) + ->example('KJAX'), + Parameter::query() + ->name('id') + ->description('ID of the ATIS audio file') + ->required(true) + ->schema(Schema::string()) + ->example('1'), + + ]; + } +} diff --git a/src/app/OpenApi/RequestBodies/TTS/GetTextToSpeechRequestBody.php b/src/app/OpenApi/RequestBodies/TTS/GetTextToSpeechRequestBody.php new file mode 100644 index 0000000..a1296a0 --- /dev/null +++ b/src/app/OpenApi/RequestBodies/TTS/GetTextToSpeechRequestBody.php @@ -0,0 +1,31 @@ +properties( + Schema::string('id') + ->example('1') + ->description('The ID of the ATIS audio file.') + ->required(), + Schema::string('icao') + ->example('KJAX') + ->description('The ICAO code of the airport.') + ->required(), + ); + + return RequestBody::create('GetTextToSpeech') + ->description('Get TTS file for an airport.') + ->content( + MediaType::json()->schema($response) + ); + } +} diff --git a/src/app/OpenApi/Responses/TTS/GetTextToSpeech/ErrorGetTextToSpeechResponse.php b/src/app/OpenApi/Responses/TTS/GetTextToSpeech/ErrorGetTextToSpeechResponse.php new file mode 100644 index 0000000..fdff2ac --- /dev/null +++ b/src/app/OpenApi/Responses/TTS/GetTextToSpeech/ErrorGetTextToSpeechResponse.php @@ -0,0 +1,26 @@ +properties( + Schema::string('status')->example('error'), + Schema::string('message')->example('ATIS audio file not found.'), + Schema::integer('code')->example(404), + Schema::object('data')->nullable() + ); + + return Response::create('TTSError', 'Error getting TTS file.') + ->description('Error getting TTS file.') + ->content(MediaType::json()->schema($response)); + } +} diff --git a/src/app/OpenApi/Responses/TTS/GetTextToSpeech/SuccessResponse.php b/src/app/OpenApi/Responses/TTS/GetTextToSpeech/SuccessResponse.php new file mode 100644 index 0000000..92a940f --- /dev/null +++ b/src/app/OpenApi/Responses/TTS/GetTextToSpeech/SuccessResponse.php @@ -0,0 +1,33 @@ +properties( + Schema::string('status')->example('success'), + Schema::string('message')->example('ATIS audio file found.'), + Schema::integer('code')->example(200), + Schema::object('data')->properties( + Schema::string('id')->example('1'), + Schema::string('name')->example('KJAX_ATIS_A_261700Z.mp3'), + Schema::string('url')->example('/storage/atis/1/KJAX_ATIS_A_261700Z.mp3'), + Schema::string('expires_at')->example('2021-01-01 00:00:00'), + ) + ); + + return Response::create('GetTextToSpeechSuccess') + ->description('Get TTS file for an airport.') + ->content( + MediaType::json()->schema($response) + ); + } +} diff --git a/src/public/lib/js/redbeard.js b/src/public/lib/js/redbeard.js index 57b750c..078f3f9 100644 --- a/src/public/lib/js/redbeard.js +++ b/src/public/lib/js/redbeard.js @@ -5,10 +5,10 @@ $(document).ready(function () { a = $(this).val(); if (o.test(a)) { $(this).val(a.replace(o, "")); - t-- + t--; } if (this.type !== "checkbox") { - this.setSelectionRange(t, t) + this.setSelectionRange(t, t); } }); @@ -19,7 +19,7 @@ $(document).ready(function () { */ function copy(text) { output = $(text).html(); - navigator.clipboard.writeText(output) + navigator.clipboard.writeText(output); } /** @@ -104,8 +104,9 @@ $(document).ready(function () { - ${t.data.map(function (t) { - return ` + ${t.data + .map(function (t) { + return ` ${t.runway} ${t.wind_dir} @@ -113,15 +114,22 @@ $(document).ready(function () { - ` - }).join("")} + `; + }) + .join("")} `; - $("#runway-output").html(Modal("Runway List for " + icao.toUpperCase(), table, "runway-modal")); + $("#runway-output").html( + Modal( + "Runway List for " + icao.toUpperCase(), + table, + "runway-modal" + ) + ); $("#runway-modal").modal("show"); - $(".loading").hide() - }) + $(".loading").hide(); + }); }); $("#atis-input").submit(function (t) { @@ -129,24 +137,29 @@ $(document).ready(function () { t.preventDefault(); icao = $("#icao").val(); ident = $("#ident").val(); - $.post(`/api/v1/airports/${icao}/atis`, $("#atis-input").serialize(), function (t) { - if (t.status == "error" || t.code != 200) { - $("#atis-output").html(ErrorModal(t.message, "atis-modal")); - $("#atis-modal").modal("show"); - $(".loading").hide(); - return; - } + $.post( + `/api/v1/airports/${icao}/atis`, + $("#atis-input").serialize(), + function (t) { + if (t.status == "error" || t.code != 200) { + $("#atis-output").html(ErrorModal(t.message, "atis-modal")); + $("#atis-modal").modal("show"); + $(".loading").hide(); + return; + } - if (t.data == "") { - $("#atis-output").html(ErrorModal("API returned empty data. Please try again.")); - $("#atis-modal").modal("show"); - $(".loading").hide(); - return; - } + if (t.data == "") { + $("#atis-output").html( + ErrorModal("API returned empty data. Please try again.") + ); + $("#atis-modal").modal("show"); + $(".loading").hide(); + return; + } - atis = t.data.spoken; + atis = t.data.spoken; - success = ` + success = `