mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-08 14:43:24 +00:00
feat: allow adding links via ip
This commit is contained in:
9
app/links/validators/base_link_validator.ts
Normal file
9
app/links/validators/base_link_validator.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import vine from '@vinejs/vine';
|
||||||
|
|
||||||
|
export const baseLinkValidator = vine.object({
|
||||||
|
name: vine.string().trim().minLength(1).maxLength(254),
|
||||||
|
description: vine.string().trim().maxLength(300).optional(),
|
||||||
|
url: vine.string().url({ require_tld: false }).trim(),
|
||||||
|
favorite: vine.boolean(),
|
||||||
|
collectionId: vine.number(),
|
||||||
|
});
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
|
import { baseLinkValidator } from '#links/validators/base_link_validator';
|
||||||
import vine from '@vinejs/vine';
|
import vine from '@vinejs/vine';
|
||||||
|
|
||||||
export const createLinkValidator = vine.compile(
|
export const createLinkValidator = vine.compile(
|
||||||
vine.object({
|
vine.object({
|
||||||
name: vine.string().trim().minLength(1).maxLength(254),
|
...baseLinkValidator.getProperties(),
|
||||||
description: vine.string().trim().maxLength(300).optional(),
|
|
||||||
url: vine.string().trim(),
|
|
||||||
favorite: vine.boolean(),
|
|
||||||
collectionId: vine.number(),
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import { params } from '#core/validators/params_object';
|
import { params } from '#core/validators/params_object';
|
||||||
|
import { baseLinkValidator } from '#links/validators/base_link_validator';
|
||||||
import vine from '@vinejs/vine';
|
import vine from '@vinejs/vine';
|
||||||
|
|
||||||
export const updateLinkValidator = vine.compile(
|
export const updateLinkValidator = vine.compile(
|
||||||
vine.object({
|
vine.object({
|
||||||
name: vine.string().trim().minLength(1).maxLength(254),
|
...baseLinkValidator.getProperties(),
|
||||||
description: vine.string().trim().maxLength(300).optional(),
|
|
||||||
url: vine.string().trim(),
|
|
||||||
favorite: vine.boolean(),
|
|
||||||
collectionId: vine.number(),
|
|
||||||
|
|
||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ interface FormCollectionProps extends FormLayoutProps {
|
|||||||
handleSubmit: () => void;
|
handleSubmit: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MantineFormCollection({
|
export function MantineFormCollection({
|
||||||
data,
|
data,
|
||||||
errors,
|
errors,
|
||||||
disableInputs = false,
|
disableInputs = false,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ interface FormLinkProps extends FormLayoutProps {
|
|||||||
handleSubmit: () => void;
|
handleSubmit: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MantineFormLink({
|
export function FormLink({
|
||||||
data,
|
data,
|
||||||
errors,
|
errors,
|
||||||
collections,
|
collections,
|
||||||
@@ -83,7 +83,7 @@ export default function MantineFormLink({
|
|||||||
value: id.toString(),
|
value: id.toString(),
|
||||||
}))}
|
}))}
|
||||||
onChange={(value) => setData('collectionId', value)}
|
onChange={(value) => setData('collectionId', value)}
|
||||||
value={data.collectionId.toString()}
|
value={data.collectionId?.toString()}
|
||||||
readOnly={disableInputs}
|
readOnly={disableInputs}
|
||||||
mt="md"
|
mt="md"
|
||||||
searchable
|
searchable
|
||||||
|
|||||||
@@ -16,15 +16,50 @@ export const appendResourceId = (
|
|||||||
) => `${url}${resourceId ? `/${resourceId}` : ''}`;
|
) => `${url}${resourceId ? `/${resourceId}` : ''}`;
|
||||||
|
|
||||||
export function isValidHttpUrl(urlParam: string) {
|
export function isValidHttpUrl(urlParam: string) {
|
||||||
let url;
|
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}(:\d+)?(\/.*)?(\?.*)?(#[^#]*)?$/;
|
||||||
|
const domainRegex =
|
||||||
|
/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(:\d+)?(\/.*)?(\?.*)?(#[^#]*)?$/;
|
||||||
|
const simpleDomainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$/;
|
||||||
|
|
||||||
|
let urlToTest = urlParam.trim();
|
||||||
|
|
||||||
|
if (urlToTest.startsWith('http://') || urlToTest.startsWith('https://')) {
|
||||||
try {
|
try {
|
||||||
url = new URL(urlParam);
|
const url = new URL(urlToTest);
|
||||||
|
return url.protocol === 'http:' || url.protocol === 'https:';
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return url.protocol === 'http:' || url.protocol === 'https:';
|
if (ipv4Regex.test(urlToTest)) {
|
||||||
|
try {
|
||||||
|
new URL(`http://${urlToTest}`);
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domainRegex.test(urlToTest)) {
|
||||||
|
try {
|
||||||
|
new URL(`http://${urlToTest}`);
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simpleDomainRegex.test(urlToTest)) {
|
||||||
|
try {
|
||||||
|
new URL(`http://${urlToTest}`);
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateShareUrl = (
|
export const generateShareUrl = (
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useForm } from '@inertiajs/react';
|
|||||||
import { route } from '@izzyjs/route/client';
|
import { route } from '@izzyjs/route/client';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import MantineFormLink from '~/components/form/form_link';
|
import { FormLink } from '~/components/form/form_link';
|
||||||
import useSearchParam from '~/hooks/use_search_param';
|
import useSearchParam from '~/hooks/use_search_param';
|
||||||
import { isValidHttpUrl } from '~/lib/navigation';
|
import { isValidHttpUrl } from '~/lib/navigation';
|
||||||
import { Collection } from '~/types/app';
|
import { Collection } from '~/types/app';
|
||||||
@@ -38,7 +38,7 @@ export default function CreateLinkPage({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MantineFormLink
|
<FormLink
|
||||||
title={t('link.create')}
|
title={t('link.create')}
|
||||||
textSubmitButton={t('form.create')}
|
textSubmitButton={t('form.create')}
|
||||||
canSubmit={canSubmit}
|
canSubmit={canSubmit}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useForm } from '@inertiajs/react';
|
import { useForm } from '@inertiajs/react';
|
||||||
import { route } from '@izzyjs/route/client';
|
import { route } from '@izzyjs/route/client';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import MantineFormLink from '~/components/form/form_link';
|
import { FormLink } from '~/components/form/form_link';
|
||||||
import { LinkWithCollection } from '~/types/app';
|
import { LinkWithCollection } from '~/types/app';
|
||||||
|
|
||||||
export default function DeleteLinkPage({ link }: { link: LinkWithCollection }) {
|
export default function DeleteLinkPage({ link }: { link: LinkWithCollection }) {
|
||||||
@@ -22,7 +22,7 @@ export default function DeleteLinkPage({ link }: { link: LinkWithCollection }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MantineFormLink
|
<FormLink
|
||||||
title={t('link.delete')}
|
title={t('link.delete')}
|
||||||
textSubmitButton={t('form.delete')}
|
textSubmitButton={t('form.delete')}
|
||||||
canSubmit={!processing}
|
canSubmit={!processing}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useForm } from '@inertiajs/react';
|
|||||||
import { route } from '@izzyjs/route/client';
|
import { route } from '@izzyjs/route/client';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import MantineFormLink from '~/components/form/form_link';
|
import { FormLink } from '~/components/form/form_link';
|
||||||
import { isValidHttpUrl } from '~/lib/navigation';
|
import { isValidHttpUrl } from '~/lib/navigation';
|
||||||
import { Collection, Link } from '~/types/app';
|
import { Collection, Link } from '~/types/app';
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ export default function EditLinkPage({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MantineFormLink
|
<FormLink
|
||||||
title={t('link.edit')}
|
title={t('link.edit')}
|
||||||
textSubmitButton={t('form.update')}
|
textSubmitButton={t('form.update')}
|
||||||
canSubmit={canSubmit}
|
canSubmit={canSubmit}
|
||||||
|
|||||||
Reference in New Issue
Block a user