import axios from 'axios'; import { Field, Form, Formik } from 'formik'; import dynamic from 'next/dynamic'; import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { useToasts } from 'react-toast-notifications'; import useSWR from 'swr'; import * as Yup from 'yup'; import globalMessages from '../../../../i18n/globalMessages'; import Button from '../../../Common/Button'; import LoadingSpinner from '../../../Common/LoadingSpinner'; import NotificationTypeSelector from '../../../NotificationTypeSelector'; const JSONEditor = dynamic(() => import('../../../JSONEditor'), { ssr: false }); const defaultPayload = { notification_type: '{{notification_type}}', subject: '{{subject}}', message: '{{message}}', image: '{{image}}', email: '{{notifyuser_email}}', username: '{{notifyuser_username}}', avatar: '{{notifyuser_avatar}}', '{{media}}': { media_type: '{{media_type}}', tmdbId: '{{media_tmdbid}}', imdbId: '{{media_imdbid}}', tvdbId: '{{media_tvdbid}}', status: '{{media_status}}', status4k: '{{media_status4k}}', }, '{{extra}}': [], '{{request}}': { request_id: '{{request_id}}', requestedBy_email: '{{requestedBy_email}}', requestedBy_username: '{{requestedBy_username}}', requestedBy_avatar: '{{requestedBy_avatar}}', }, }; const messages = defineMessages({ agentenabled: 'Enable Agent', webhookUrl: 'Webhook URL', authheader: 'Authorization Header', validationJsonPayloadRequired: 'You must provide a valid JSON payload', webhooksettingssaved: 'Webhook notification settings saved successfully!', webhooksettingsfailed: 'Webhook notification settings failed to save.', testsent: 'Webhook test notification sent!', resetPayload: 'Reset to Default', resetPayloadSuccess: 'JSON payload reset successfully!', customJson: 'JSON Payload', templatevariablehelp: 'Template Variable Help', validationWebhookUrl: 'You must provide a valid URL', }); const NotificationsWebhook: React.FC = () => { const intl = useIntl(); const { addToast } = useToasts(); const { data, error, revalidate } = useSWR( '/api/v1/settings/notifications/webhook' ); const NotificationsWebhookSchema = Yup.object().shape({ webhookUrl: Yup.string() .when('enabled', { is: true, then: Yup.string() .nullable() .required(intl.formatMessage(messages.validationWebhookUrl)), otherwise: Yup.string().nullable(), }) .matches( // eslint-disable-next-line /^(https?:)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i, intl.formatMessage(messages.validationWebhookUrl) ), jsonPayload: Yup.string() .when('enabled', { is: true, then: Yup.string() .nullable() .required(intl.formatMessage(messages.validationJsonPayloadRequired)), otherwise: Yup.string().nullable(), }) .test( 'validate-json', intl.formatMessage(messages.validationJsonPayloadRequired), (value) => { try { JSON.parse(value ?? ''); return true; } catch (e) { return false; } } ), }); if (!data && !error) { return ; } return ( { try { await axios.post('/api/v1/settings/notifications/webhook', { enabled: values.enabled, types: values.types, options: { webhookUrl: values.webhookUrl, jsonPayload: JSON.stringify(values.jsonPayload), authHeader: values.authHeader, }, }); addToast(intl.formatMessage(messages.webhooksettingssaved), { appearance: 'success', autoDismiss: true, }); } catch (e) { addToast(intl.formatMessage(messages.webhooksettingsfailed), { appearance: 'error', autoDismiss: true, }); } finally { revalidate(); } }} > {({ errors, touched, isSubmitting, values, isValid, setFieldValue, setFieldTouched, }) => { const resetPayload = () => { setFieldValue( 'jsonPayload', JSON.stringify(defaultPayload, undefined, ' ') ); addToast(intl.formatMessage(messages.resetPayloadSuccess), { appearance: 'info', autoDismiss: true, }); }; const testSettings = async () => { await axios.post('/api/v1/settings/notifications/webhook/test', { enabled: true, types: values.types, options: { webhookUrl: values.webhookUrl, jsonPayload: JSON.stringify(values.jsonPayload), authHeader: values.authHeader, }, }); addToast(intl.formatMessage(messages.testsent), { appearance: 'info', autoDismiss: true, }); }; return (
{errors.webhookUrl && touched.webhookUrl && (
{errors.webhookUrl}
)}
setFieldValue('jsonPayload', value)} value={values.jsonPayload} onBlur={() => setFieldTouched('jsonPayload')} />
{errors.jsonPayload && touched.jsonPayload && (
{errors.jsonPayload}
)}
{intl.formatMessage(messages.templatevariablehelp)}
setFieldValue('types', newTypes)} />
); }}
); }; export default NotificationsWebhook;