diff --git a/github/flujo/snyk_scan.js b/.github/workflows/snyk_scan.yml similarity index 100% rename from github/flujo/snyk_scan.js rename to .github/workflows/snyk_scan.yml diff --git a/github/flujo/sonar_scan.js b/.github/workflows/sonar_scan.yml similarity index 100% rename from github/flujo/sonar_scan.js rename to .github/workflows/sonar_scan.yml diff --git a/cosas.js b/cosas.js deleted file mode 100644 index 8b93182..0000000 --- a/cosas.js +++ /dev/null @@ -1,368 +0,0 @@ -const CHARACTER_ID = "character"; - -const character_es = { - "cardsLayoutTemplateData": { - "type": "object", - "properties": { - "backgroundImage": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "headerTitle": "Rodrigo Del Angel Gerardo", - "headerSubtitle": "20210658", - "headerAttributionImage": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "primaryText": "Personajes sobresalientes", - "listItems": [ - { - "primaryText": "Hayao Miyazaki", - "secondaryText": "Renombrado director de cine", - "thumbnailImage": "https://static.euronews.com/articles/stories/08/30/05/18/1200x675_cmsv2_79166748-9efd-5333-8740-797bc205849e-8300518.jpg" - }, - { - "primaryText": "Haruki Murakami", - "secondaryText": "Escritor contemporaneo", - "thumbnailImage": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTJbtsCXuHTfrFnOptux89Vko0rSWKCUG-RUg&s" - }, - { - "primaryText": "Yoko Ono", - "secondaryText": "Artista, música y activista", - "thumbnailImage": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Yoko_Ono_2011_SXSW.jpg/1200px-Yoko_Ono_2011_SXSW.jpg" - }, - { - "primaryText": "Akira Kurosawa", - "secondaryText": "Uno de los cineastas más importantes de Japón", - "thumbnailImage": "https://cdn.zendalibros.com/wp-content/uploads/akira-kurosawa.jpg" - }, - { - "primaryText": "Naomi Osaka", - "secondaryText": "Tenista profesional", - "thumbnailImage": "https://imagenes.elpais.com/resizer/v2/IYJ3CINWD6KACUN44EUF563VOE.jpg?auth=f8437eeffa43cc829155d9f130000b1535e23e8ca0f8cb7ebedc11a6f162b4b9&width=414" - } - ] - } - } -}; - -const COSTUME_ID = "costume"; - -const costume_es = { - "simpleTextTemplateData": { - "type": "object", - "properties": { - "backgroundImage": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "foregroundImageLocation": "left", - "foregroundImageSource": "https://www.nippon.com/es/ncommon/contents/behind/122249/122249.jpg", - "headerTitle": "Rodrigo Del Angel Gerardo", - "headerSubtitle": "20210658", - "hintText": "Prueba, \"Alexa, Dime una descripcion de Tokyo\"", - "headerAttributionImage": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "primaryText": "El kimono es una prenda tradicional japonesa que se usa en ocasiones formales como bodas, ceremonias del té y festivales. Existen diferentes tipos de kimono para hombres y mujeres, cada uno con su estilo y detalles únicos. Las mujeres suelen usar kimonos coloridos y decorativos, mientras que los hombres optan por diseños más sobrios.", - "textAlignment": "start", - "titleText": "Kimono" - } - } -}; - -// Este es un template de video -const DESCRIPTION_ID = "description"; - -const description_Es = { - "videoPlayerTemplateData": { - "type": "object", - "properties": { - "backgroundImage": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "displayFullscreen": false, - "headerTitle": "Rodrigo Del Angel Gerardo", - "headerSubtitle": "20210658", - "logoUrl": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "videoControlType": "skip", - "videoSources": [ - "https://youtu.be/MaGgSxjCt6U?si=avznMMoAqnXSW85L", - "https://youtu.be/JiSNuPMqHWQ?si=dEBzcnXnhu1FxSvt", - "https://youtu.be/8PVbgqQMdlk?si=IJkH2HNKVhTos5A0" - ], - "sliderType": "determinate" - } - } -}; - -const ERROR_ID = "error"; - -const error = { - "headlineTemplateData": { - "type": "object", - "objectId": "headlineSample", - "properties": { - "backgroundImage": { - "contentDescription": null, - "smallSourceUrl": null, - "largeSourceUrl": null, - "sources": [ - { - "url": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "size": "large" - } - ] - }, - "textContent": { - "primaryText": { - "type": "PlainText", - "text": "Lo siento, tuve problemas para hacer lo que me pediste. Inténtalo de nuevo." - } - }, - "logoUrl": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "hintText": "Prueba, \"Alexa, Dime lugares turisticos de Tokyo\"" - } - } -}; - -const EXIT_ID = "exit"; - -const exit = { - "headlineTemplateData": { - "type": "object", - "objectId": "headlineSample", - "properties": { - "backgroundImage": { - "contentDescription": null, - "smallSourceUrl": null, - "largeSourceUrl": null, - "sources": [ - { - "url": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "size": "large" - } - ] - }, - "textContent": { - "primaryText": { - "type": "PlainText", - "text": "Hasta luego, vuelve pronto para mas informacion de Tokyo." - } - }, - "logoUrl": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "hintText": ",Te deseamos excelente dia." - } - } -}; - -const FOOD_ID = "food"; - -const food = { - "imageListData": { - "type": "object", - "objectId": "imageListSample", - "backgroundImage": { - "contentDescription": null, - "smallSourceUrl": null, - "largeSourceUrl": null, - "sources": [ - { - "url": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "size": "large" - } - ] - }, - "title": "Rodrigo Del Angel Gerardo", - "listItems": [ - { - "primaryText": "Sushi", - "imageSource": "https://media.tacdn.com/media/attractions-splice-spp-674x446/09/28/c6/40.jpg" - }, - { - "primaryText": "Ramen", - "imageSource": "https://media.timeout.com/images/105591139/750/562/image.jpg" - }, - { - "primaryText": "Tempura", - "imageSource": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQS1XJ8u4MUvJbOJcu4H75srXzjO8BT_IFJ-Q&s" - }, - { - "primaryText": "Sashimi", - "imageSource": "https://jw-webmagazine.com/wp-content/uploads/2019/12/93d34990255c92d5ba645698d005d697_l-min.jpg" - }, - { - "primaryText": "Okonomiyaki", - "imageSource": "https://static.wixstatic.com/media/0a76a3_760a64922d3644ca9eef2a7ef29b06d4~mv2.jpeg/v1/fill/w_816,h_544,al_c,lg_1,q_85/0a76a3_760a64922d3644ca9eef2a7ef29b06d4~mv2.jpeg" - } - ], - "logoUrl": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "hintText": "Try, \"Alexa, Dime una descripción de Tokyo\"" - } -}; - -const HELP_ID = "help"; - -const help = { - "headlineTemplateData": { - "type": "object", - "objectId": "headlineSample", - "properties": { - "backgroundImage": { - "contentDescription": null, - "smallSourceUrl": null, - "largeSourceUrl": null, - "sources": [ - { - "url": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "size": "large" - } - ] - }, - "textContent": { - "primaryText": { - "type": "PlainText", - "text": "Puedes probar diciendo, \"Quiero que me describas Japón\"" - } - }, - "logoUrl": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "hintText": "¿Puedo ayudarte en algo mas?" - } - } -}; - -//este es un reproductor de musica -const MUSIC_ID = "music"; - -const music = { - "audioPlayerTemplateData": { - "type": "object", - "properties": { - "audioControlType": "jump30", - "audioSources": [ - "https://youtu.be/WLRd3-Lli3c?si=m2yLwNH0SOcFFyHZ", - "https://d2o906d8ln7ui1.cloudfront.net/images/response_builder/Wall-Flowers-and-Roses.wav" - ], - "backgroundImage": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "coverImageSource": "https://www.tokyoweekender.com/wp-content/uploads/2018/10/Sound-Museum-Vision-Tokyo-Weekender.jpg", - "headerTitle": "Rodrigo Del Angel Gerardo", - "logoUrl": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "primaryText": "Mix Tokyo", - "secondaryText": "My favourite album", - "sliderType": "determinate" - } - } -}; - -const PLACES_ID = "places"; - -const places = { - "textListData": { - "type": "object", - "objectId": "textListSample", - "backgroundImage": { - "contentDescription": null, - "smallSourceUrl": null, - "largeSourceUrl": null, - "sources": [ - { - "url": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "size": "large" - } - ] - }, - "title": "Rodrigo Del Angel Gerardo", - "listItems": [ - { - "primaryText": "Templo Senso-ji: Este antiguo templo budista, ubicado en Asakusa, es uno de los más famosos y visitados de Tokyo." - }, - { - "primaryText": "Torre de Tokyo: Un ícono de la ciudad, esta torre de comunicaciones y observatorio ofrece vistas panorámicas de Tokyo." - }, - { - "primaryText": "Shibuya Crossing: La intersección más famosa del mundo, conocida por su frenético cruce peatonal y la estatua de Hachiko." - }, - { - "primaryText": "Parque Ueno: Un amplio parque público conocido por su zoológico, museos y especialmente por los cerezos en flor durante la primavera." - }, - { - "primaryText": "Palacio Imperial: La residencia oficial del Emperador de Japón, rodeada de jardines y fosos, se encuentra en el corazón de Tokyo." - } - ], - "logoUrl": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png" - } -}; - -const WELCOME_ID = "welcome"; - -const welcome = { - "headlineTemplateData": { - "type": "object", - "objectId": "headlineSample", - "properties": { - "backgroundImage": { - "contentDescription": null, - "smallSourceUrl": null, - "largeSourceUrl": null, - "sources": [ - { - "url": "https://c.wallhere.com/photos/fa/ce/Japan_anime_street_light_temple_light_effects_dark-1954129.jpg!d", - "size": "large" - } - ] - }, - "textContent": { - "primaryText": { - "type": "PlainText", - "text": "Bienvenido a informacion de Tokyo" - } - }, - "logoUrl": "https://www.uthh.edu.mx/imagenes/carreras/Logos_Carreras/2015061214431910_gal.png", - "hintText": "Prueba, \"Alexa, Dime una descripcion de Tokyo\"" - } - } -}; -const createDirectivePayload = (aplDocumentId, dataSources = {}, tokenId = "documentToken") => { - return { - type: "Alexa.Presentation.APL.RenderDocument", - token: tokenId, - document: { - type: "Link", - src: "doc://alexa/apl/documents/" + aplDocumentId - }, - datasources: dataSources - } -}; - - -// Lugares esta mal -const VIDEOEJEMPLO_ID = "videoejemplo"; - -const videoejemplo = { - "videoPlayerTemplateData": { - "type": "object", - "properties": { - "backgroundImage": "https://d2o906d8ln7ui1.cloudfront.net/images/response_builder/background-green.png", - "displayFullscreen": false, - "headerTitle": "How to care for potted plants", - "headerSubtitle": "", - "logoUrl": "https://d2o906d8ln7ui1.cloudfront.net/images/response_builder/logo-world-of-plants-2.png", - "videoControlType": "skip", - "videoSources": [ - "https://www.dropbox.com/scl/fi/xqoatqzsouj0437xa3xm8/Por-qu-vive-tanta-gente-en-Tokio_.mp4?rlkey=kxhmzcems1478z4lwxacyz1j7&st=h6uwx4ok&dl=1", - "https://d2o906d8ln7ui1.cloudfront.net/videos/AdobeStock_292807382.mov" - ], - "sliderType": "determinate" - } - } -}; - - -const AUDIO_ID = " "; - -const audioejemplo = { - "audioPlayerTemplateData": { - "type": "object", - "properties": { - "audioControlType": "skip", - "audioSources": [ - "https://www.dropbox.com/scl/fi/818eud0t0txgrd0d1tos6/Y2meta.app-Tani-Yuuki-MV-128-kbps.mp3?rlkey=w54ddnncap29mawd8ef97i9x5&st=sn20lhb5&dl=1", - "https://d2o906d8ln7ui1.cloudfront.net/images/response_builder/Wall-Flowers-and-Roses.wav" - ], - "backgroundImage": "https://d2o906d8ln7ui1.cloudfront.net/images/response_builder/background-rose.png", - "coverImageSource": "https://d2o906d8ln7ui1.cloudfront.net/images/response_builder/card-rose.jpeg", - "headerTitle": "My favorite flower songs", - "logoUrl": "https://d2o906d8ln7ui1.cloudfront.net/images/response_builder/logo-world-of-plants-2.png", - "primaryText": "Roses", - "secondaryText": "My favourite album", - "sliderType": "determinate" - } - } -}; diff --git a/github/flujo/tests_api.js b/github/flujo/tests_api.js deleted file mode 100644 index 2fca9ff..0000000 --- a/github/flujo/tests_api.js +++ /dev/null @@ -1,62 +0,0 @@ -name: Run Tests - -on: - pull_request: - push: - branches: - - main - workflow_dispatch: - -permissions: write-all - -jobs: - test: - name: Run Tests - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - token: ${{ secrets.MY_GH_TOKEN }} - - - name: Set up Node.js - uses: actions/setup-node@v2 - with: - node-version: '17' - - - name: Install dependencies - run: npm install - - - name: Run tests - env: - # trae las variabes del .env - URI_MONGO: ${{ secrets.URI_MONGO }} - JWT_SECRET: ${{ secrets.JWT_SECRET }} - JWT_REFRESH: ${{ secrets.JWT_REFRESH }} - CLOUD_NAME: ${{ secrets.CLOUD_NAME }} - API_KEY: ${{ secrets.API_KEY }} - API_SECRET: ${{ secrets.API_SECRET }} - USER: ${{ secrets.USER }} - PASSWORD: ${{ secrets.PASSWORD }} - PLANTILLA: ${{ secrets.PLANTILLA }} - SMS_TOKEN: ${{ secrets.SMS_TOKEN }} - run: | - set +e - # ejecuta las pruebas - set NODE_OPTIONS=--experimental-vm-modules && npx jest - # guarda el valor de las pruebas que pude ser 0 o 1 - TEST_RESULT=$? - set -e - # si el resultado es diferente de 0 - if [ $TEST_RESULT -ne 0 ]; then - echo "Tests failed. Reverting to previous version..." - git config --global user.email "20210658@uthh.edu.mx" - git config --global user.name "rodrigo3829l" - # regresa al commit anterior - git reset --hard HEAD^ - git push https://github.com/rodrigo3829l/db_api_mygarden_llc.git --force - else - echo "Tests passed." - fi diff --git a/ingles.js b/ingles.js deleted file mode 100644 index 8d38d2d..0000000 --- a/ingles.js +++ /dev/null @@ -1,1125 +0,0 @@ -const Alexa = require('ask-sdk-core'); -const axios = require('axios'); -const moment = require('moment'); -const i18n = require('i18next'); -const sprintf = require('i18next-sprintf-postprocessor'); -const aplEs = require('./apl-es'); -const aplEn = require('./apl-en'); -const CANCEL_ID = "CancelarServicio"; -const FAREWELL_ID = "Farewell"; -const HELP_ID = "Help"; -const LOGIN_ID = "Login"; -const SERVICE_DETAILS_ID = "ServiceDetails"; -const STATUS_SERVICES_ID = "StatusServices"; -const WELCOME_ID = "Welcome"; -const ERROR_ID = "Error"; - -const persistenceAdapter = getPersistenceAdapter(); - -function getPersistenceAdapter() { - function isAlexaHosted() { - return process.env.S3_PERSISTENCE_BUCKET ? true : false; - } - const tableName = 'user_data_table'; - if (isAlexaHosted()) { - const { S3PersistenceAdapter } = require('ask-sdk-s3-persistence-adapter'); - return new S3PersistenceAdapter({ - bucketName: process.env.S3_PERSISTENCE_BUCKET - }); - } else { - const { DynamoDbPersistenceAdapter } = require('ask-sdk-dynamodb-persistence-adapter'); - return new DynamoDbPersistenceAdapter({ - tableName: tableName, - createTable: true - }); - } -} - -const languageStrings = require('./languaje.js') -const translateStatusToSpanish = (status) => { - switch(status) { - case 'quoting': - return 'cotizando'; - case 'quoted': - return 'cotizado'; - case 'development': - return 'en desarrollo'; - case 'finish': - return 'finalizado'; - default: - return 'estado desconocido'; - } -}; - -const translateStatusToEnglish = (status) => { - switch(status) { - case 'cotizando': - return 'quoting'; - case 'cotizado': - return 'quoted'; - case 'en desarrollo': - return 'development'; - case 'finalizado': - return 'finish'; - default: - return 'unknown status'; - } -} - -const createDirectivePayload = (aplDocumentId, dataSources = {}, tokenId = "documentToken") => { - return { - type: "Alexa.Presentation.APL.RenderDocument", - token: tokenId, - document: { - type: "Link", - src: "doc://alexa/apl/documents/" + aplDocumentId - }, - datasources: dataSources - } -}; - -const LocalizationInterceptor = { - process(handlerInput) { - const localizationClient = i18n.init({ - lng: handlerInput.requestEnvelope.request.locale, - resources: languageStrings - }); - localizationClient.localize = function (...args) { - const value = i18n.t(...args); - return value; - }; - handlerInput.t = function (...args) { - return localizationClient.localize(...args); - }; - } -}; - -const getAplData = (locale) => { - if (locale.startsWith('es')) { - return aplEs; - } else { - return aplEn; - } -}; - -const LaunchRequestHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'; - }, - async handle(handlerInput) { - try { - const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); - const persistentAttributes = await handlerInput.attributesManager.getPersistentAttributes(); - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - - if (persistentAttributes.token && persistentAttributes.name) { - sessionAttributes.token = persistentAttributes.token; - sessionAttributes.name = persistentAttributes.name; - sessionAttributes.email = persistentAttributes.email; - handlerInput.attributesManager.setSessionAttributes(sessionAttributes); - - try { - const response = await axios.get('https://db-api-mygarden.onrender.com/api/user/refresh', { - headers: { - Authorization: `Bearer ${persistentAttributes.token}`, - rol: 'client', - } - }); - - if (response.data.token) { - sessionAttributes.token = response.data.token; - sessionAttributes.name = response.data.name; - sessionAttributes.email = response.data.email; - handlerInput.attributesManager.setSessionAttributes(sessionAttributes); - - handlerInput.attributesManager.setPersistentAttributes({ - token: response.data.token, - name: response.data.name, - email: response.data.email - }); - await handlerInput.attributesManager.savePersistentAttributes(); - - const speakOutput = handlerInput.t('WELCOME_BACK_MSG', { name: response.data.name }); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const aplDirective = createDirectivePayload(WELCOME_ID, aplData.Welcome); - handlerInput.responseBuilder.addDirective(aplDirective); - } - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } else { - throw new Error('Invalid token refresh response'); - } - } catch (error) { - console.log('Token refresh failed:', error); - const speakOutput = handlerInput.t('SESSION_EXPIRED_MSG'); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput); - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } else { - const speakOutput = handlerInput.t('WELCOME_MSG'); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const aplDirective = createDirectivePayload(WELCOME_ID, aplData.Welcome); - handlerInput.responseBuilder.addDirective(aplDirective); - } - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } catch (error) { - console.error('Error in LaunchRequestHandler:', error); - return handlerInput.responseBuilder - .addDirective({ - type: 'Dialog.Delegate', - updatedIntent: { - name: 'ErrorHandler' - } - }) - .getResponse(); - } - } -}; -const HelpIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent'; - }, - handle(handlerInput) { - try { - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const aplDirective = createDirectivePayload(HELP_ID, aplData.Help); - handlerInput.responseBuilder.addDirective(aplDirective); - } - const speakOutput = handlerInput.t('HELP_MSG'); - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } catch (error) { - console.error('Error in HelpIntentHandler:', error); - return handlerInput.responseBuilder - .addDirective({ - type: 'Dialog.Delegate', - updatedIntent: { - name: 'ErrorHandler' - } - }) - .getResponse(); - } - } -}; - - -const CancelAndStopIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent' - || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent'); - }, - handle(handlerInput) { - try { - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const aplDirective = createDirectivePayload(FAREWELL_ID, aplData.Farewell); - handlerInput.responseBuilder.addDirective(aplDirective); - } - const speakOutput = handlerInput.t('GOODBYE_MSG'); - - return handlerInput.responseBuilder - .speak(speakOutput) - .withShouldEndSession(true) // Finaliza la sesión - .getResponse(); - } catch (error) { - console.error('Error in CancelAndStopIntentHandler:', error); - return handlerInput.responseBuilder - .addDirective({ - type: 'Dialog.Delegate', - updatedIntent: { - name: 'ErrorHandler' - } - }) - .getResponse(); - } - } -}; - -const FallbackIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.FallbackIntent'; - }, - handle(handlerInput) { - try { - const speakOutput = handlerInput.t('FALLBACK_MSG'); - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } catch (error) { - console.error('Error in FallbackIntentHandler:', error); - return handlerInput.responseBuilder - .addDirective({ - type: 'Dialog.Delegate', - updatedIntent: { - name: 'ErrorHandler' - } - }) - .getResponse(); - } - } -}; - -const SessionEndedRequestHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest'; - }, - handle(handlerInput) { - try { - console.log(`~~~~ Session ended: ${JSON.stringify(handlerInput.requestEnvelope)}`); - return handlerInput.responseBuilder.getResponse(); - } catch (error) { - console.error('Error in SessionEndedRequestHandler:', error); - return handlerInput.responseBuilder - .addDirective({ - type: 'Dialog.Delegate', - updatedIntent: { - name: 'ErrorHandler' - } - }) - .getResponse(); - } - } -}; - -const IntentReflectorHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'; - }, - handle(handlerInput) { - try { - const intentName = Alexa.getIntentName(handlerInput.requestEnvelope); - const speakOutput = `You just triggered ${intentName}`; - - return handlerInput.responseBuilder - .speak(speakOutput) - .getResponse(); - } catch (error) { - console.error('Error in IntentReflectorHandler:', error); - return handlerInput.responseBuilder - .addDirective({ - type: 'Dialog.Delegate', - updatedIntent: { - name: 'ErrorHandler' - } - }) - .getResponse(); - } - } -}; - - -const ErrorHandler = { - canHandle() { - return true; - }, - handle(handlerInput, error) { - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(handlerInput.t('ERROR_MSG')) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - const speakOutput = handlerInput.t('ERROR_MSG'); - console.log(`~~~~ Error handled: ${JSON.stringify(error)}`); - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } -}; - -const CaptureEmailIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && - Alexa.getIntentName(handlerInput.requestEnvelope) === 'CaptureEmailIntent'; - }, - handle(handlerInput) { - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - const intentName = Alexa.getIntentName(handlerInput.requestEnvelope); - - // Agregar manejo de la guía de uso - const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); - if (sessionAttributes.guideUserActive) { - const speakOutput = handlerInput.t('GUIDE_USER_MSG', { intentName: intentName }); - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.Login(); - const aplDirective = createDirectivePayload(LOGIN_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - - const email = "202106581@gmail.com"; - - if (!validateEmail(email)) { - const speakOutput = handlerInput.t('EMAIL_INVALID_MSG'); - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - sessionAttributes.email = email; - handlerInput.attributesManager.setSessionAttributes(sessionAttributes); - - const speakOutput = handlerInput.t('EMAIL_RECEIVED_MSG'); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.Login(speakOutput); - const aplDirective = createDirectivePayload(LOGIN_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } -}; - -const CapturePasswordIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && - Alexa.getIntentName(handlerInput.requestEnvelope) === 'CapturePasswordIntent'; - }, - async handle(handlerInput) { - console.log("hola") - const password = "Drop345terra#"; - const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); - const email = sessionAttributes.email; - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - const intentName = Alexa.getIntentName(handlerInput.requestEnvelope); - - // Agregar manejo de la guía de uso - if (sessionAttributes.guideUserActive) { - const speakOutput = handlerInput.t('GUIDE_USER_MSG', { intentName: intentName }); - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - try { - const response = await axios.post( - "https://db-api-mygarden.onrender.com/api/user/login", - { - email: email, - password: password, - department: "client", - } - ); - - if (response.data.token) { - const token = response.data.token; - const name = response.data.name; - - sessionAttributes.token = token; - sessionAttributes.name = name; - handlerInput.attributesManager.setSessionAttributes(sessionAttributes); - - await handlerInput.attributesManager.setPersistentAttributes({ - token: token, - name: name, - email: email, - }); - await handlerInput.attributesManager.savePersistentAttributes(); - - const speakOutput = handlerInput.t("LOGIN_SUCCESS_MSG", { name: name }); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)["Alexa.Presentation.APL"]) { - const apl = aplData.Login(speakOutput); - const aplDirective = createDirectivePayload(LOGIN_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } else { - const speakOutput = handlerInput.t("LOGIN_FAILURE_MSG", { - error: response.data.error, - }); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)["Alexa.Presentation.APL"]) { - const apl = aplData.Login(speakOutput); - const aplDirective = createDirectivePayload(LOGIN_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } catch (error) { - console.log(error); - const speakOutput = handlerInput.t("LOGIN_ERROR_MSG"); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)["Alexa.Presentation.APL"]) { - const apl = aplData.Login(speakOutput); - const aplDirective = createDirectivePayload(LOGIN_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } -}; - - - -const StatusServicesIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'StatusServicesIntent'; - }, - async handle(handlerInput) { - const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); - const token = sessionAttributes.token; - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - const isSpanish = locale.startsWith('es'); - - if (!token) { - // Si el token no está disponible, pedir al usuario que inicie sesión - const speakOutput = "No hay token"; - return handlerInput.responseBuilder - .speak(speakOutput) - .getResponse(); - } - - try { - const response = await makeApiRequest(token); - - if (response.success) { - const services = response.services; - - if (services.length === 0) { - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(handlerInput.t('NO_SERVICES_MSG')) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - const speakOutput = handlerInput.t('NO_SERVICES_MSG'); - return handlerInput.responseBuilder - .speak(speakOutput) - .getResponse(); - } - - // Guardar servicios en la sesión - //handlerInput.attributesManager.setSessionAttributes({ services, currentIndex: 0 }); - - // Mostrar primeros 6 servicios - const firstSixServices = services.slice(0, 6); - const apl = aplData.StatusServices(firstSixServices); - const aplDirective = createDirectivePayload(STATUS_SERVICES_ID, apl); - - let speechOutput = handlerInput.t('SERVICES_STATUS_MSG'); - firstSixServices.forEach(service => { - const formattedDate = moment(service.dates.scheduledTime).format('DD/MM/YYYY'); - if (isSpanish) { - speechOutput += `El servicio ${service.description} con fecha reservada el ${formattedDate} está ${translateStatusToSpanish(service.status)}. `; - } else { - speechOutput += `The service ${service.description} scheduled on ${formattedDate} is ${service.status}. `; - } - }); - - return handlerInput.responseBuilder - .speak(speechOutput) - .addDirective(aplDirective) - .reprompt(speechOutput) - .getResponse(); - } else { - const errorMsg = response.msg || handlerInput.t('SERVICES_FETCH_ERROR_MSG'); - const speakOutput = `${handlerInput.t('ERROR_MSG')} ${errorMsg}`; - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput); - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } catch (error) { - console.error('Error in StatusServicesIntentHandler:', error); - const speakOutput = handlerInput.t('SERVICES_FETCH_ERROR_MSG'); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput); - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } -}; - - -const StatusSpecificServicesIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'StatusSpecificServicesIntent'; - }, - async handle(handlerInput) { - const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); - const token = sessionAttributes.token; - const status = Alexa.getSlotValue(handlerInput.requestEnvelope, 'status'); - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - const translateStatus = (locale.startsWith('es')) ? translateStatusToEnglish(status) : status; - if (!token) { - // Si el token no está disponible, pedir al usuario que inicie sesión - const speakOutput = "No hay token"; - return handlerInput.responseBuilder - .speak(speakOutput) - .getResponse(); - } - try { - const response = await makeApiRequest(token); - - if (response.success) { - const services = response.services.filter(service => service.status.toLowerCase() === translateStatus.toLowerCase()); - - if (services.length === 0) { - const speakOutput = handlerInput.t('NO_SERVICES_STATUS_MSG', { status }); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput); - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .getResponse(); - } - - // Guardar servicios en la sesión - // handlerInput.attributesManager.setSessionAttributes({ services, currentIndex: 0 }); - - // Mostrar primeros 6 servicios - const firstSixServices = services.slice(0, 6); - const apl = aplData.StatusServices(firstSixServices); - const aplDirective = createDirectivePayload(STATUS_SERVICES_ID, apl); - - let speechOutput = handlerInput.t('SERVICES_WITH_STATUS_MSG', { status }); - firstSixServices.forEach(service => { - const formattedDate = moment(service.dates.scheduledTime).format('DD/MM/YYYY'); - speechOutput += handlerInput.t('SERVICE_DETAIL_MSG', { description: service.description, date: formattedDate }); - }); - - return handlerInput.responseBuilder - .speak(speechOutput) - .addDirective(aplDirective) - .reprompt(speechOutput) - .getResponse(); - } else { - const errorMsg = response.msg || handlerInput.t('SERVICES_ERROR_MSG'); - const speakOutput = `${handlerInput.t('ERROR_MSG')} ${errorMsg}`; - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput); - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } catch (error) { - console.error('Error in StatusSpecificServicesIntentHandler:', error); - const speakOutput = handlerInput.t('SERVICES_ERROR_MSG'); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput); - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } -}; - - -const ShowNextServicesIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'ShowNextServicesIntent'; - }, - handle(handlerInput) { - const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); - const { services, currentIndex } = sessionAttributes; - - const nextIndex = currentIndex + 6; - const nextServices = services.slice(nextIndex, nextIndex + 6); - - if (nextServices.length === 0) { - const speakOutput = handlerInput.t('NO_MORE_SERVICES_MSG'); - return handlerInput.responseBuilder - .speak(speakOutput) - .getResponse(); - } - - // Actualizar índice actual - //handlerInput.attributesManager.setSessionAttributes({ services, currentIndex: nextIndex }); - - const aplData = getAplData(Alexa.getLocale(handlerInput.requestEnvelope)); - const apl = aplData.StatusServices(nextServices); - const aplDirective = createDirectivePayload(STATUS_SERVICES_ID, apl); - - let speechOutput = handlerInput.t('NEXT_SERVICES_MSG'); - nextServices.forEach(service => { - const formattedDate = moment(service.dates.scheduledTime).format('DD/MM/YYYY'); - if (Alexa.getLocale(handlerInput.requestEnvelope).startsWith('es')) { - speechOutput += `El servicio ${service.description} con fecha reservada el ${formattedDate} está ${translateStatusToSpanish(service.status)}. `; - } else { - speechOutput += `The service ${service.description} scheduled on ${formattedDate} is ${service.status}. `; - } - }); - - return handlerInput.responseBuilder - .speak(speechOutput) - .addDirective(aplDirective) - .reprompt(speechOutput) - .getResponse(); - } -}; - - - -const ServiceDetailsIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'ServiceDetailsIntent'; - }, - async handle(handlerInput) { - const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); - const token = sessionAttributes.token; - const serviceDescription = Alexa.getSlotValue(handlerInput.requestEnvelope, 'serviceDescription'); - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - if (!token) { - // Si el token no está disponible, pedir al usuario que inicie sesión - const speakOutput = "No hay token"; - return handlerInput.responseBuilder - .speak(speakOutput) - .getResponse(); - } - try { - // Obtener todos los servicios - const response = await makeApiRequest(token); - - if (!response.success) { - const errorMsg = response.msg || handlerInput.t('SERVICES_ERROR_MSG'); - const speakOutput = `${handlerInput.t('ERROR_MSG')} ${errorMsg}`; - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - const allServices = response.services; - const matchingService = allServices.find(service => service.description.toLowerCase() === serviceDescription.toLowerCase()); - - if (!matchingService) { - const speakOutput = handlerInput.t('SERVICE_NOT_FOUND_MSG', { serviceDescription }); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - const serviceId = matchingService._id; - - // Obtener detalles del servicio específico - const serviceDetailsResponse = await axios.get(`https://db-api-mygarden.onrender.com/api/schedule/scheduleservice/${serviceId}`, { - headers: { - Authorization: `Bearer ${token}`, - rol: 'client', - } - }); - - if (!serviceDetailsResponse.data.success) { - const errorMsg = serviceDetailsResponse.data.msg || handlerInput.t('SERVICES_ERROR_MSG'); - const speakOutput = `${handlerInput.t('ERROR_MSG')} ${errorMsg}`; - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - const service = serviceDetailsResponse.data.newService; - let speechOutput = handlerInput.t('SERVICE_DETAIL_INFO_MSG', { service: service.service, description: service.description }); - let datasource - const translateStatus = (locale.startsWith('es')) ? translateStatusToEnglish(service.status) : service.status - if (service.status !== 'quoting') { - datasource = aplData.ServiceDetails( - service.img, - translateStatus, - service.quote, - service.pending, - service.additionalCosts.labor, - service.description, - service.service, - service.additionalCosts.machinery - ); - const formattedDate = moment(service.dates.scheduledTime).format('DD/MM/YYYY'); - speechOutput += handlerInput.t('SERVICE_STATUS_MSG', { status: translateStatus, scheduledDate: formattedDate, quote: service.quote }); - - if (service.products && service.products.length > 0) { - speechOutput += handlerInput.t('SERVICE_PRODUCTS_MSG'); - service.products.forEach(product => { - speechOutput += handlerInput.t('SERVICE_PRODUCT_DETAIL_MSG', { product: product.product, quantity: product.quantity, total: product.total }); - }); - } - - if (service.additionalCosts) { - speechOutput += handlerInput.t('SERVICE_ADDITIONAL_COSTS_MSG', { labor: service.additionalCosts.labor, machinery: service.additionalCosts.machinery }); - } - - if (service.employeds && service.employeds.length > 0) { - speechOutput += handlerInput.t('SERVICE_EMPLOYEES_MSG', { employees: service.employeds.join(', ') }); - } - } else { - datasource = aplData.ServiceDetails( - service.img, - translateStatus, - 0, - 0, - 0, - service.description, - service.service, - 0 - ); - const formattedDate = moment(service.dates.scheduledTime).format('DD/MM/YYYY'); - const reservedDate = moment(service.dates.reserved).format('DD/MM/YYYY'); - speechOutput += handlerInput.t('SERVICE_QUOTING_STATUS_MSG', { status: translateStatus, scheduledDate: formattedDate, reservedDate: reservedDate }); - } - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - - const aplDirective = createDirectivePayload(SERVICE_DETAILS_ID, datasource); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speechOutput) - .reprompt(speechOutput) - .getResponse(); - - } catch (error) { - console.error('Error in ServiceDetailsIntentHandler:', error); - console.log(error); - const speakOutput = handlerInput.t('SERVICES_ERROR_MSG'); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } -}; - -const CancelServiceIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'CancelServiceIntent'; - }, - async handle(handlerInput) { - const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); - const token = sessionAttributes.token; - const serviceDescription = Alexa.getSlotValue(handlerInput.requestEnvelope, 'serviceDescription'); - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - if (!token) { - // Si el token no está disponible, pedir al usuario que inicie sesión - const speakOutput = "No hay token"; - return handlerInput.responseBuilder - .speak(speakOutput) - .getResponse(); - } - try { - const response = await makeApiRequest(token); - - if (!response.success) { - const errorMsg = response.msg || handlerInput.t('CANCEL_SERVICE_ERROR_MSG'); - const speakOutput = `${errorMsg}`; - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - const allServices = response.services; - const matchingService = allServices.find(service => service.description.toLowerCase() === serviceDescription.toLowerCase()); - - if (!matchingService) { - const speakOutput = handlerInput.t('CANCEL_SERVICE_NOT_FOUND_MSG', { serviceDescription }); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - const serviceId = matchingService._id; - - // Cancelar el servicio específico - const cancelServiceResponse = await axios.put(`https://db-api-mygarden.onrender.com/api/schedule/cancel/${serviceId}`, {}, { - headers: { - Authorization: `Bearer ${token}`, - rol: 'client', - } - }); - - if (!cancelServiceResponse.data.success) { - const errorMsg = cancelServiceResponse.data.msg || handlerInput.t('CANCEL_SERVICE_ERROR_MSG'); - const speakOutput = `${errorMsg}`; - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - - const successMsg = cancelServiceResponse.data.msg || handlerInput.t('CANCEL_SERVICE_SUCCESS_MSG'); - const speakOutput = successMsg; - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.CancelService - const aplDirective = createDirectivePayload(CANCEL_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } catch (error) { - console.error('Error in cencelsERVICE:', error); - const speakOutput = handlerInput.t('CANCEL_SERVICE_ERROR_MSG'); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(speakOutput) - .getResponse(); - } - } -}; - -const makeApiRequest = async (token) => { - try { - console.log('Making API request with token:', token); - const response = await axios.get('https://db-api-mygarden.onrender.com/api/schedule/userservices', { - headers: { - Authorization: `Bearer ${token}`, - rol: 'client', - } - }); - console.log('API response:', response.data); - return response.data; - } catch (error) { - console.error('Error making API request:', error); - throw error; - } -}; - - -const validateEmail = (email) => { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); -}; - -const LoadAttributesRequestInterceptor = { - async process(handlerInput) { - if (handlerInput.requestEnvelope.session['new']) { - const { attributesManager } = handlerInput; - const persistentAttributes = await attributesManager.getPersistentAttributes() || {}; - console.log('Loaded persistent attributes:', persistentAttributes); - handlerInput.attributesManager.setSessionAttributes(persistentAttributes); - } - } -}; - -const SaveAttributesResponseInterceptor = { - async process(handlerInput, response) { - const { attributesManager } = handlerInput; - const sessionAttributes = attributesManager.getSessionAttributes(); - const shouldEndSession = (typeof response.shouldEndSession === "undefined" ? true : response.shouldEndSession); - if (shouldEndSession || handlerInput.requestEnvelope.request.type === 'SessionEndedRequest') { - attributesManager.setPersistentAttributes(sessionAttributes); - await attributesManager.savePersistentAttributes(); - console.log('Saved persistent attributes:', sessionAttributes); - } - } -}; - - -const LogOutIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'LogOutIntent'; - }, - async handle(handlerInput) { - // Clear session and persistent attributes - handlerInput.attributesManager.setSessionAttributes({}); - handlerInput.attributesManager.setPersistentAttributes({}); - await handlerInput.attributesManager.savePersistentAttributes(); - - const speakOutput = handlerInput.t('LOGOUT_SUCCESS_MSG'); - - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const apl = aplData.ErrorMesaje(speakOutput) - const aplDirective = createDirectivePayload(ERROR_ID, apl); - handlerInput.responseBuilder.addDirective(aplDirective); - } - - return handlerInput.responseBuilder - .speak(speakOutput) - .withShouldEndSession(true) - .getResponse(); - } -}; -const GuideUserIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'GuideUserIntent'; - }, - handle(handlerInput) { - const speakOutput = handlerInput.t('GUIDE_USER_MSG'); - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - - /*if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const aplDirective = createDirectivePayload(GUIDE_USER_ID, aplData.GuideUser); - handlerInput.responseBuilder.addDirective(aplDirective); - }*/ - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(handlerInput.t('GUIDE_USER_REPROMPT')) - .getResponse(); - } -}; -const ServiceStatusListIntentHandler = { - canHandle(handlerInput) { - return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' - && Alexa.getIntentName(handlerInput.requestEnvelope) === 'ServiceStatusListIntent'; - }, - handle(handlerInput) { - const speakOutput = handlerInput.t('SERVICE_STATUS_LIST_MSG'); - const locale = Alexa.getLocale(handlerInput.requestEnvelope); - const aplData = getAplData(locale); - - /*if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) { - const aplDirective = createDirectivePayload(SERVICE_STATUS_LIST_ID, aplData.ServiceStatusList); - handlerInput.responseBuilder.addDirective(aplDirective); - }*/ - - return handlerInput.responseBuilder - .speak(speakOutput) - .reprompt(handlerInput.t('SERVICE_STATUS_LIST_REPROMPT')) - .getResponse(); - } -}; - - -exports.handler = Alexa.SkillBuilders.custom() - .addRequestHandlers( - LaunchRequestHandler, - CaptureEmailIntentHandler, - CapturePasswordIntentHandler, - StatusServicesIntentHandler, - StatusSpecificServicesIntentHandler, - ServiceDetailsIntentHandler, - ShowNextServicesIntentHandler, - CancelServiceIntentHandler, - LogOutIntentHandler, - GuideUserIntentHandler, - ServiceStatusListIntentHandler, - CancelAndStopIntentHandler, - FallbackIntentHandler, - SessionEndedRequestHandler, - IntentReflectorHandler - ) - .addRequestInterceptors( - LocalizationInterceptor, - LoadAttributesRequestInterceptor // Agregar aquí el interceptor de carga de atributos - ) - .addResponseInterceptors( - SaveAttributesResponseInterceptor // Agregar aquí el interceptor de guardado de atributos - ) - .addErrorHandlers(ErrorHandler) - .withPersistenceAdapter(persistenceAdapter) - .lambda(); \ No newline at end of file