mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
fix(ui): Add additional URL & email input validation (#843)
This commit is contained in:
@@ -14,13 +14,13 @@ const messages = defineMessages({
|
||||
saving: 'Saving…',
|
||||
agentenabled: 'Enable Agent',
|
||||
webhookUrl: 'Webhook URL',
|
||||
validationWebhookUrlRequired: 'You must provide a webhook URL',
|
||||
webhookUrlPlaceholder: 'Server Settings → Integrations → Webhooks',
|
||||
discordsettingssaved: 'Discord notification settings saved!',
|
||||
discordsettingsfailed: 'Discord notification settings failed to save.',
|
||||
testsent: 'Test notification sent!',
|
||||
test: 'Test',
|
||||
notificationtypes: 'Notification Types',
|
||||
validationWebhookUrl: 'You must provide a valid URL',
|
||||
});
|
||||
|
||||
const NotificationsDiscord: React.FC = () => {
|
||||
@@ -31,9 +31,9 @@ const NotificationsDiscord: React.FC = () => {
|
||||
);
|
||||
|
||||
const NotificationsDiscordSchema = Yup.object().shape({
|
||||
webhookUrl: Yup.string().required(
|
||||
intl.formatMessage(messages.validationWebhookUrlRequired)
|
||||
),
|
||||
webhookUrl: Yup.string()
|
||||
.required(intl.formatMessage(messages.validationWebhookUrl))
|
||||
.url(intl.formatMessage(messages.validationWebhookUrl)),
|
||||
});
|
||||
|
||||
if (!data && !error) {
|
||||
|
@@ -12,7 +12,6 @@ import NotificationTypeSelector from '../../NotificationTypeSelector';
|
||||
const messages = defineMessages({
|
||||
save: 'Save Changes',
|
||||
saving: 'Saving…',
|
||||
validationFromRequired: 'You must provide a sender address',
|
||||
validationSmtpHostRequired: 'You must provide an SMTP host',
|
||||
validationSmtpPortRequired: 'You must provide an SMTP port',
|
||||
agentenabled: 'Enable Agent',
|
||||
@@ -31,6 +30,7 @@ const messages = defineMessages({
|
||||
'SSL should be disabled on standard TLS connections (port 587)',
|
||||
senderName: 'Sender Name',
|
||||
notificationtypes: 'Notification Types',
|
||||
validationEmail: 'You must provide a valid email address',
|
||||
});
|
||||
|
||||
const NotificationsEmail: React.FC = () => {
|
||||
@@ -41,9 +41,9 @@ const NotificationsEmail: React.FC = () => {
|
||||
);
|
||||
|
||||
const NotificationsEmailSchema = Yup.object().shape({
|
||||
emailFrom: Yup.string().required(
|
||||
intl.formatMessage(messages.validationFromRequired)
|
||||
),
|
||||
emailFrom: Yup.string()
|
||||
.required(intl.formatMessage(messages.validationEmail))
|
||||
.email(intl.formatMessage(messages.validationEmail)),
|
||||
smtpHost: Yup.string().required(
|
||||
intl.formatMessage(messages.validationSmtpHostRequired)
|
||||
),
|
||||
|
@@ -15,7 +15,6 @@ const messages = defineMessages({
|
||||
saving: 'Saving…',
|
||||
agentenabled: 'Enable Agent',
|
||||
webhookUrl: 'Webhook URL',
|
||||
validationWebhookUrlRequired: 'You must provide a webhook URL',
|
||||
webhookUrlPlaceholder: 'Webhook URL',
|
||||
slacksettingssaved: 'Slack notification settings saved!',
|
||||
slacksettingsfailed: 'Slack notification settings failed to save.',
|
||||
@@ -25,6 +24,7 @@ const messages = defineMessages({
|
||||
settingupslackDescription:
|
||||
'To use Slack notifications, you will need to create an <WebhookLink>Incoming Webhook</WebhookLink> integration and use the provided webhook URL below.',
|
||||
notificationtypes: 'Notification Types',
|
||||
validationWebhookUrl: 'You must provide a valid URL',
|
||||
});
|
||||
|
||||
const NotificationsSlack: React.FC = () => {
|
||||
@@ -35,9 +35,9 @@ const NotificationsSlack: React.FC = () => {
|
||||
);
|
||||
|
||||
const NotificationsSlackSchema = Yup.object().shape({
|
||||
webhookUrl: Yup.string().required(
|
||||
intl.formatMessage(messages.validationWebhookUrlRequired)
|
||||
),
|
||||
webhookUrl: Yup.string()
|
||||
.required(intl.formatMessage(messages.validationWebhookUrl))
|
||||
.url(intl.formatMessage(messages.validationWebhookUrl)),
|
||||
});
|
||||
|
||||
if (!data && !error) {
|
||||
|
@@ -37,7 +37,6 @@ const messages = defineMessages({
|
||||
agentenabled: 'Enable Agent',
|
||||
webhookUrl: 'Webhook URL',
|
||||
authheader: 'Authorization Header',
|
||||
validationWebhookUrlRequired: 'You must provide a webhook URL',
|
||||
validationJsonPayloadRequired: 'You must provide a JSON Payload',
|
||||
webhookUrlPlaceholder: 'Remote webhook URL',
|
||||
webhooksettingssaved: 'Webhook notification settings saved!',
|
||||
@@ -49,6 +48,7 @@ const messages = defineMessages({
|
||||
resetPayloadSuccess: 'JSON reset to default payload.',
|
||||
customJson: 'Custom JSON Payload',
|
||||
templatevariablehelp: 'Template Variable Help',
|
||||
validationWebhookUrl: 'You must provide a valid URL',
|
||||
});
|
||||
|
||||
const NotificationsWebhook: React.FC = () => {
|
||||
@@ -59,9 +59,13 @@ const NotificationsWebhook: React.FC = () => {
|
||||
);
|
||||
|
||||
const NotificationsWebhookSchema = Yup.object().shape({
|
||||
webhookUrl: Yup.string().required(
|
||||
intl.formatMessage(messages.validationWebhookUrlRequired)
|
||||
),
|
||||
webhookUrl: Yup.string()
|
||||
.required(intl.formatMessage(messages.validationWebhookUrl))
|
||||
.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})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
|
||||
intl.formatMessage(messages.validationWebhookUrl)
|
||||
),
|
||||
jsonPayload: Yup.string()
|
||||
.required(intl.formatMessage(messages.validationJsonPayloadRequired))
|
||||
.test('validate-json', 'Invalid JSON', (value) => {
|
||||
|
@@ -52,6 +52,8 @@ const messages = defineMessages({
|
||||
preventSearch: 'Disable Auto-Search',
|
||||
validationApplicationUrl: 'You must provide a valid URL',
|
||||
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||
validationBaseUrlLeadingSlash: 'Base URL must have a leading slash',
|
||||
validationBaseUrlTrailingSlash: 'Base URL must not end in a trailing slash',
|
||||
});
|
||||
|
||||
interface TestResponse {
|
||||
@@ -119,6 +121,27 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
return true;
|
||||
}
|
||||
),
|
||||
baseUrl: Yup.string()
|
||||
.test(
|
||||
'leading-slash',
|
||||
intl.formatMessage(messages.validationBaseUrlLeadingSlash),
|
||||
(value) => {
|
||||
if (value && value?.substr(0, 1) !== '/') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
)
|
||||
.test(
|
||||
'no-trailing-slash',
|
||||
intl.formatMessage(messages.validationBaseUrlTrailingSlash),
|
||||
(value) => {
|
||||
if (value?.substr(value.length - 1) === '/') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
const testConnection = useCallback(
|
||||
|
@@ -52,6 +52,8 @@ const messages = defineMessages({
|
||||
preventSearch: 'Disable Auto-Search',
|
||||
validationApplicationUrl: 'You must provide a valid URL',
|
||||
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||
validationBaseUrlLeadingSlash: 'Base URL must have a leading slash',
|
||||
validationBaseUrlTrailingSlash: 'Base URL must not end in a trailing slash',
|
||||
});
|
||||
|
||||
interface TestResponse {
|
||||
@@ -116,6 +118,27 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
return true;
|
||||
}
|
||||
),
|
||||
baseUrl: Yup.string()
|
||||
.test(
|
||||
'leading-slash',
|
||||
intl.formatMessage(messages.validationBaseUrlLeadingSlash),
|
||||
(value) => {
|
||||
if (value && value?.substr(0, 1) !== '/') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
)
|
||||
.test(
|
||||
'no-trailing-slash',
|
||||
intl.formatMessage(messages.validationBaseUrlTrailingSlash),
|
||||
(value) => {
|
||||
if (value?.substr(value.length - 1) === '/') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
const testConnection = useCallback(
|
||||
|
@@ -11,6 +11,7 @@ import PermissionEdit from '../PermissionEdit';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { UserType } from '../../../server/constants/user';
|
||||
import PageTitle from '../Common/PageTitle';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
export const messages = defineMessages({
|
||||
edituser: 'Edit User',
|
||||
@@ -23,6 +24,7 @@ export const messages = defineMessages({
|
||||
saving: 'Saving…',
|
||||
usersaved: 'User saved!',
|
||||
userfail: 'Something went wrong while saving the user.',
|
||||
validationEmail: 'You must provide a valid email address',
|
||||
});
|
||||
|
||||
const UserEdit: React.FC = () => {
|
||||
@@ -43,6 +45,12 @@ const UserEdit: React.FC = () => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [user]);
|
||||
|
||||
const UserEditSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.required(intl.formatMessage(messages.validationEmail))
|
||||
.email(intl.formatMessage(messages.validationEmail)),
|
||||
});
|
||||
|
||||
if (!user && !error) {
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
@@ -54,6 +62,7 @@ const UserEdit: React.FC = () => {
|
||||
username: user?.username,
|
||||
email: user?.email,
|
||||
}}
|
||||
validationSchema={UserEditSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.put(`/api/v1/user/${user?.id}`, {
|
||||
@@ -78,7 +87,7 @@ const UserEdit: React.FC = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ isSubmitting, handleSubmit }) => (
|
||||
{({ errors, touched, isSubmitting, handleSubmit }) => (
|
||||
<Form>
|
||||
<PageTitle title={intl.formatMessage(messages.edituser)} />
|
||||
<div>
|
||||
@@ -122,6 +131,9 @@ const UserEdit: React.FC = () => {
|
||||
<div className="flex max-w-lg rounded-md shadow-sm">
|
||||
<Field id="email" name="email" type="text" readOnly />
|
||||
</div>
|
||||
{errors.email && touched.email && (
|
||||
<div className="error">{errors.email}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
|
@@ -51,7 +51,6 @@ const messages = defineMessages({
|
||||
createuser: 'Create User',
|
||||
creating: 'Creating…',
|
||||
create: 'Create',
|
||||
validationemailrequired: 'Must enter a valid email address',
|
||||
validationpasswordminchars:
|
||||
'Password is too short; should be a minimum of 8 characters',
|
||||
usercreatedfailed: 'Something went wrong while creating the user.',
|
||||
@@ -62,6 +61,7 @@ const messages = defineMessages({
|
||||
passwordinfodescription:
|
||||
'Email notifications need to be configured and enabled in order to automatically generate passwords.',
|
||||
autogeneratepassword: 'Automatically generate password',
|
||||
validationEmail: 'You must provide a valid email address',
|
||||
});
|
||||
|
||||
const UserList: React.FC = () => {
|
||||
@@ -171,8 +171,8 @@ const UserList: React.FC = () => {
|
||||
|
||||
const CreateUserSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email()
|
||||
.required(intl.formatMessage(messages.validationemailrequired)),
|
||||
.required(intl.formatMessage(messages.validationEmail))
|
||||
.email(intl.formatMessage(messages.validationEmail)),
|
||||
password: Yup.lazy((value) =>
|
||||
!value ? Yup.string() : Yup.string().min(8)
|
||||
),
|
||||
|
@@ -237,7 +237,7 @@
|
||||
"components.Settings.Notifications.NotificationsSlack.slacksettingssaved": "Slack notification settings saved!",
|
||||
"components.Settings.Notifications.NotificationsSlack.test": "Test",
|
||||
"components.Settings.Notifications.NotificationsSlack.testsent": "Test notification sent!",
|
||||
"components.Settings.Notifications.NotificationsSlack.validationWebhookUrlRequired": "You must provide a webhook URL",
|
||||
"components.Settings.Notifications.NotificationsSlack.validationWebhookUrl": "You must provide a valid URL",
|
||||
"components.Settings.Notifications.NotificationsSlack.webhookUrl": "Webhook URL",
|
||||
"components.Settings.Notifications.NotificationsSlack.webhookUrlPlaceholder": "Webhook URL",
|
||||
"components.Settings.Notifications.NotificationsWebhook.agentenabled": "Enable Agent",
|
||||
@@ -252,7 +252,7 @@
|
||||
"components.Settings.Notifications.NotificationsWebhook.test": "Test",
|
||||
"components.Settings.Notifications.NotificationsWebhook.testsent": "Test notification sent!",
|
||||
"components.Settings.Notifications.NotificationsWebhook.validationJsonPayloadRequired": "You must provide a JSON payload",
|
||||
"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrlRequired": "You must provide a webhook URL",
|
||||
"components.Settings.Notifications.NotificationsWebhook.validationWebhookUrl": "You must provide a valid URL",
|
||||
"components.Settings.Notifications.NotificationsWebhook.webhookUrl": "Webhook URL",
|
||||
"components.Settings.Notifications.NotificationsWebhook.webhookUrlPlaceholder": "Remote webhook URL",
|
||||
"components.Settings.Notifications.NotificationsWebhook.webhooksettingsfailed": "Webhook notification settings failed to save.",
|
||||
@@ -284,10 +284,10 @@
|
||||
"components.Settings.Notifications.testsent": "Test notification sent!",
|
||||
"components.Settings.Notifications.validationBotAPIRequired": "You must provide a Bot API key",
|
||||
"components.Settings.Notifications.validationChatIdRequired": "You must provide a Chat ID",
|
||||
"components.Settings.Notifications.validationFromRequired": "You must provide a sender address",
|
||||
"components.Settings.Notifications.validationEmail": "You must provide a valid email address",
|
||||
"components.Settings.Notifications.validationSmtpHostRequired": "You must provide an SMTP host",
|
||||
"components.Settings.Notifications.validationSmtpPortRequired": "You must provide an SMTP port",
|
||||
"components.Settings.Notifications.validationWebhookUrlRequired": "You must provide a webhook URL",
|
||||
"components.Settings.Notifications.validationWebhookUrl": "You must provide a valid URL",
|
||||
"components.Settings.Notifications.webhookUrl": "Webhook URL",
|
||||
"components.Settings.Notifications.webhookUrlPlaceholder": "Server Settings → Integrations → Webhooks",
|
||||
"components.Settings.RadarrModal.add": "Add Server",
|
||||
@@ -327,6 +327,8 @@
|
||||
"components.Settings.RadarrModal.validationApiKeyRequired": "You must provide an API key",
|
||||
"components.Settings.RadarrModal.validationApplicationUrl": "You must provide a valid URL",
|
||||
"components.Settings.RadarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||
"components.Settings.RadarrModal.validationBaseUrlLeadingSlash": "Base URL must have a leading slash",
|
||||
"components.Settings.RadarrModal.validationBaseUrlTrailingSlash": "Base URL must not end in a trailing slash",
|
||||
"components.Settings.RadarrModal.validationHostnameRequired": "You must provide a hostname/IP",
|
||||
"components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "You must select a minimum availability",
|
||||
"components.Settings.RadarrModal.validationNameRequired": "You must provide a server name",
|
||||
@@ -413,6 +415,8 @@
|
||||
"components.Settings.SonarrModal.validationApiKeyRequired": "You must provide an API key",
|
||||
"components.Settings.SonarrModal.validationApplicationUrl": "You must provide a valid URL",
|
||||
"components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
|
||||
"components.Settings.SonarrModal.validationBaseUrlLeadingSlash": "Base URL must have a leading slash",
|
||||
"components.Settings.SonarrModal.validationBaseUrlTrailingSlash": "Base URL must not end in a trailing slash",
|
||||
"components.Settings.SonarrModal.validationHostnameRequired": "You must provide a hostname/IP",
|
||||
"components.Settings.SonarrModal.validationNameRequired": "You must provide a server name",
|
||||
"components.Settings.SonarrModal.validationPortRequired": "You must provide a port",
|
||||
@@ -576,6 +580,7 @@
|
||||
"components.UserEdit.userfail": "Something went wrong while saving the user.",
|
||||
"components.UserEdit.username": "Display Name",
|
||||
"components.UserEdit.usersaved": "User saved!",
|
||||
"components.UserEdit.validationEmail": "You must provide a valid email address",
|
||||
"components.UserList.admin": "Admin",
|
||||
"components.UserList.autogeneratepassword": "Automatically generate password",
|
||||
"components.UserList.bulkedit": "Bulk Edit",
|
||||
@@ -610,7 +615,7 @@
|
||||
"components.UserList.users": "Users",
|
||||
"components.UserList.userssaved": "Users saved!",
|
||||
"components.UserList.usertype": "User Type",
|
||||
"components.UserList.validationemailrequired": "Must enter a valid email address",
|
||||
"components.UserList.validationEmail": "You must provide a valid email address",
|
||||
"components.UserList.validationpasswordminchars": "Password is too short; should be a minimum of 8 characters",
|
||||
"i18n.advanced": "Advanced",
|
||||
"i18n.approve": "Approve",
|
||||
|
Reference in New Issue
Block a user