From f88fa2c232ecee3ba6b2e014c83843eec874eeab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Guillot?= Date: Thu, 13 Jun 2024 18:08:35 +0200 Subject: [PATCH] Added: - Messenger, Mercure - chapter download flow (lelscan only) --- assets/controllers/alert_controller.js | 60 +++++++++++++++++++ .../download_chapter_controller.js | 56 +++++++++++++++++ assets/controllers/mercure_controller.js | 33 ++++++++++ config/packages/mercure.yaml | 8 +++ config/packages/messenger.yaml | 25 ++++++++ migrations/Version20240610183912.php | 46 ++++++++++++++ 6 files changed, 228 insertions(+) create mode 100644 assets/controllers/alert_controller.js create mode 100644 assets/controllers/download_chapter_controller.js create mode 100644 assets/controllers/mercure_controller.js create mode 100644 config/packages/mercure.yaml create mode 100644 config/packages/messenger.yaml create mode 100644 migrations/Version20240610183912.php diff --git a/assets/controllers/alert_controller.js b/assets/controllers/alert_controller.js new file mode 100644 index 0000000..ae5b8d9 --- /dev/null +++ b/assets/controllers/alert_controller.js @@ -0,0 +1,60 @@ +import {Controller} from '@hotwired/stimulus'; + +/* +* The following line makes this controller "lazy": it won't be downloaded until needed +* See https://github.com/symfony/stimulus-bridge#lazy-controllers +*/ +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static targets = ['alert', 'icon', 'message'] + + connect() { + window.addEventListener('alert:show', this.showAlert.bind(this)); + } + + // ... + showAlert(event) { + const detail = event.detail; + const message = detail.message; + const level = detail.level; + + let alertClass = ""; + let iconClass = ""; + switch (level) { + case 'success': + alertClass = "bg-green-500"; + iconClass = "fa-circle-check"; + break; + case 'warning': + alertClass = "bg-yellow-500"; + iconClass = "fa-circle-exclamation"; + break; + case 'error': + alertClass = "bg-red-500"; + iconClass = "fa-circle-xmark"; + break; + case 'info': + default: + alertClass = "bg-blue-500"; + iconClass = "fa-circle-info"; + break; + } + + this.messageTarget.innerHTML = message; + this.alertTarget.classList.add(alertClass); + this.iconTarget.classList.add(iconClass); + this.alertTarget.style.display = "block"; + + setTimeout(() => { + this.alertTarget.style.opacity = 0; + + setTimeout(() => { + this.alertTarget.style.display = 'none'; + this.alertTarget.classList.remove(alertClass); + this.alertTarget.style.opacity = 1; + this.iconTarget.classList.remove(iconClass); + this.messageTarget.innerHTML = message; + }, 1000); + }, 3000); + } +} diff --git a/assets/controllers/download_chapter_controller.js b/assets/controllers/download_chapter_controller.js new file mode 100644 index 0000000..91725c5 --- /dev/null +++ b/assets/controllers/download_chapter_controller.js @@ -0,0 +1,56 @@ +import {Controller} from '@hotwired/stimulus'; + +/* +* The following line makes this controller "lazy": it won't be downloaded until needed +* See https://github.com/symfony/stimulus-bridge#lazy-controllers +*/ +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static targets = ['icon'] + + connect() { + this.defaultIconClass = this.iconTarget.classList.value; + } + + async handleClick(event) { + event.preventDefault(); + + const button = event.currentTarget; + const url = button.dataset.url; + + // Change the icon to a loader + this.iconTarget.classList.remove("fa-search"); + this.iconTarget.classList.add("fa-spinner"); + this.iconTarget.classList.add("fa-spin"); + + try { + const response = await fetch(`${url}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' + } + }); + + const data = await response.json(); + // Handle the response data as needed + if(data.error){ + this.dispatchAlert(data.error, 'error'); + }else if(data.success) { + this.dispatchAlert(data.success, 'success'); + } + } catch (error) { + console.error('Error:', error); + } finally { + // Revert the icon back to the original one + this.iconTarget.classList.value = this.defaultIconClass; + } + } + + dispatchAlert(message, level) { + const event = new CustomEvent('alert:show', { + detail: { message: message, level: level } + }); + window.dispatchEvent(event); + } +} diff --git a/assets/controllers/mercure_controller.js b/assets/controllers/mercure_controller.js new file mode 100644 index 0000000..e9befcf --- /dev/null +++ b/assets/controllers/mercure_controller.js @@ -0,0 +1,33 @@ +import {Controller} from '@hotwired/stimulus'; + +/* +* The following line makes this controller "lazy": it won't be downloaded until needed +* See https://github.com/symfony/stimulus-bridge#lazy-controllers +*/ +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + // ... + connect() { + const topic = this.data.get('topic'); + const mercureHubUrl = 'https://localhost/.well-known/mercure'; + const eventSource = new EventSource(`${mercureHubUrl}?topic=${topic}`); + + eventSource.onmessage = (event) => { + const data = JSON.parse(event.data); + console.log('Received Mercure update:', data); + + this.dispatchAlert(data.message, data.status); + }; + + eventSource.onerror = (event) => { + console.error('EventSource failed:', event); + }; + } + + dispatchAlert(message, level) { + const event = new CustomEvent('alert:show', { + detail: { message: message, level: level } + }); + window.dispatchEvent(event); + } +} diff --git a/config/packages/mercure.yaml b/config/packages/mercure.yaml new file mode 100644 index 0000000..f2a7395 --- /dev/null +++ b/config/packages/mercure.yaml @@ -0,0 +1,8 @@ +mercure: + hubs: + default: + url: '%env(MERCURE_URL)%' + public_url: '%env(MERCURE_PUBLIC_URL)%' + jwt: + secret: '%env(MERCURE_JWT_SECRET)%' + publish: '*' diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml new file mode 100644 index 0000000..ba1cd3d --- /dev/null +++ b/config/packages/messenger.yaml @@ -0,0 +1,25 @@ +framework: + messenger: + # Uncomment this (and the failed transport below) to send failed messages to this transport for later handling. + # failure_transport: failed + + transports: + # https://symfony.com/doc/current/messenger.html#transport-configuration + async: + dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + retry_strategy: + max_retries: 0 + # failed: 'doctrine://default?queue_name=failed' + # sync: 'sync://' + + routing: + # Route your messages to the transports + 'App\Message\DownloadChapter': async + +# when@test: +# framework: +# messenger: +# transports: +# # replace with your transport name here (e.g., my_transport: 'in-memory://') +# # For more Messenger testing tools, see https://github.com/zenstruck/messenger-test +# async: 'in-memory://' diff --git a/migrations/Version20240610183912.php b/migrations/Version20240610183912.php new file mode 100644 index 0000000..2cc0c70 --- /dev/null +++ b/migrations/Version20240610183912.php @@ -0,0 +1,46 @@ +addSql('CREATE TABLE messenger_messages (id BIGSERIAL NOT NULL, body TEXT NOT NULL, headers TEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, available_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, delivered_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name)'); + $this->addSql('CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at)'); + $this->addSql('CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at)'); + $this->addSql('COMMENT ON COLUMN messenger_messages.created_at IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('COMMENT ON COLUMN messenger_messages.available_at IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('COMMENT ON COLUMN messenger_messages.delivered_at IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('CREATE OR REPLACE FUNCTION notify_messenger_messages() RETURNS TRIGGER AS $$ + BEGIN + PERFORM pg_notify(\'messenger_messages\', NEW.queue_name::text); + RETURN NEW; + END; + $$ LANGUAGE plpgsql;'); + $this->addSql('DROP TRIGGER IF EXISTS notify_trigger ON messenger_messages;'); + $this->addSql('CREATE TRIGGER notify_trigger AFTER INSERT OR UPDATE ON messenger_messages FOR EACH ROW EXECUTE PROCEDURE notify_messenger_messages();'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('DROP TABLE messenger_messages'); + } +}