mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2026-01-01 20:28:40 -05:00
refactor: switch from Axios for Fetch API (#840)
* refactor: switch ExternalAPI to Fetch API * fix: add missing auth token in Plex request * fix: send proper URL params * ci: try to fix format checker * ci: ci: try to fix format checker * ci: try to fix format checker * refactor: make tautulli use the ExternalAPI class * refactor: add rate limit to fetch api * refactor: add rate limit to fetch api * refactor: switch server from axios to fetch api * refactor: switch frontend from axios to fetch api * fix: switch from URL objects to strings * fix: use the right search params for ExternalAPI * fix: better log for ExternalAPI errors * feat: add retry to external API requests * fix: try to fix network errors with IPv6 * fix: imageProxy rate limit * revert: remove retry to external API requests * feat: set IPv4 first as an option * fix(jellyfinapi): add missing argument in JellyfinAPI constructor * refactor: clean the rate limit utility
This commit is contained in:
@@ -14,7 +14,6 @@ import { DiscoverSliderType } from '@server/constants/discover';
|
||||
import type DiscoverSlider from '@server/entity/DiscoverSlider';
|
||||
import type { GenreSliderItem } from '@server/interfaces/api/discoverInterfaces';
|
||||
import type { Keyword, ProductionCompany } from '@server/models/common';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -77,11 +76,9 @@ const CreateSlider = ({ onCreate, slider }: CreateSliderProps) => {
|
||||
|
||||
const keywords = await Promise.all(
|
||||
slider.data.split(',').map(async (keywordId) => {
|
||||
const keyword = await axios.get<Keyword>(
|
||||
`/api/v1/keyword/${keywordId}`
|
||||
);
|
||||
|
||||
return keyword.data;
|
||||
const res = await fetch(`/api/v1/keyword/${keywordId}`);
|
||||
const keyword: Keyword = await res.json();
|
||||
return keyword;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -98,15 +95,13 @@ const CreateSlider = ({ onCreate, slider }: CreateSliderProps) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await axios.get<TmdbGenre[]>(
|
||||
const res = await fetch(
|
||||
`/api/v1/genres/${
|
||||
slider.type === DiscoverSliderType.TMDB_MOVIE_GENRE ? 'movie' : 'tv'
|
||||
}`
|
||||
);
|
||||
|
||||
const genre = response.data.find(
|
||||
(genre) => genre.id === Number(slider.data)
|
||||
);
|
||||
const genres: TmdbGenre[] = await res.json();
|
||||
const genre = genres.find((genre) => genre.id === Number(slider.data));
|
||||
|
||||
setDefaultDataValue([
|
||||
{
|
||||
@@ -121,11 +116,8 @@ const CreateSlider = ({ onCreate, slider }: CreateSliderProps) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await axios.get<ProductionCompany>(
|
||||
`/api/v1/studio/${slider.data}`
|
||||
);
|
||||
|
||||
const studio = response.data;
|
||||
const res = await fetch(`/api/v1/studio/${slider.data}`);
|
||||
const studio: ProductionCompany = await res.json();
|
||||
|
||||
setDefaultDataValue([
|
||||
{
|
||||
@@ -168,16 +160,17 @@ const CreateSlider = ({ onCreate, slider }: CreateSliderProps) => {
|
||||
);
|
||||
|
||||
const loadKeywordOptions = async (inputValue: string) => {
|
||||
const results = await axios.get<TmdbKeywordSearchResponse>(
|
||||
'/api/v1/search/keyword',
|
||||
const res = await fetch(
|
||||
`/api/v1/search/keyword?query=${encodeURIExtraParams(inputValue)}`,
|
||||
{
|
||||
params: {
|
||||
query: encodeURIExtraParams(inputValue),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
const results: TmdbKeywordSearchResponse = await res.json();
|
||||
|
||||
return results.data.results.map((result) => ({
|
||||
return results.results.map((result) => ({
|
||||
label: result.name,
|
||||
value: result.id,
|
||||
}));
|
||||
@@ -188,38 +181,37 @@ const CreateSlider = ({ onCreate, slider }: CreateSliderProps) => {
|
||||
return [];
|
||||
}
|
||||
|
||||
const results = await axios.get<TmdbCompanySearchResponse>(
|
||||
'/api/v1/search/company',
|
||||
const res = await fetch(
|
||||
`/api/v1/search/company?query=${encodeURIExtraParams(inputValue)}`,
|
||||
{
|
||||
params: {
|
||||
query: encodeURIExtraParams(inputValue),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
const results: TmdbCompanySearchResponse = await res.json();
|
||||
|
||||
return results.data.results.map((result) => ({
|
||||
return results.results.map((result) => ({
|
||||
label: result.name,
|
||||
value: result.id,
|
||||
}));
|
||||
};
|
||||
|
||||
const loadMovieGenreOptions = async () => {
|
||||
const results = await axios.get<GenreSliderItem[]>(
|
||||
'/api/v1/discover/genreslider/movie'
|
||||
);
|
||||
const res = await fetch('/api/v1/discover/genreslider/movie');
|
||||
const results: GenreSliderItem[] = await res.json();
|
||||
|
||||
return results.data.map((result) => ({
|
||||
return results.map((result) => ({
|
||||
label: result.name,
|
||||
value: result.id,
|
||||
}));
|
||||
};
|
||||
|
||||
const loadTvGenreOptions = async () => {
|
||||
const results = await axios.get<GenreSliderItem[]>(
|
||||
'/api/v1/discover/genreslider/tv'
|
||||
);
|
||||
const res = await fetch('/api/v1/discover/genreslider/tv');
|
||||
const results: GenreSliderItem[] = await res.json();
|
||||
|
||||
return results.data.map((result) => ({
|
||||
return results.map((result) => ({
|
||||
label: result.name,
|
||||
value: result.id,
|
||||
}));
|
||||
@@ -314,17 +306,31 @@ const CreateSlider = ({ onCreate, slider }: CreateSliderProps) => {
|
||||
onSubmit={async (values, { resetForm }) => {
|
||||
try {
|
||||
if (slider) {
|
||||
await axios.put(`/api/v1/settings/discover/${slider.id}`, {
|
||||
type: Number(values.sliderType),
|
||||
title: values.title,
|
||||
data: values.data,
|
||||
const res = await fetch(`/api/v1/settings/discover/${slider.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: Number(values.sliderType),
|
||||
title: values.title,
|
||||
data: values.data,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
} else {
|
||||
await axios.post('/api/v1/settings/discover/add', {
|
||||
type: Number(values.sliderType),
|
||||
title: values.title,
|
||||
data: values.data,
|
||||
const res = await fetch('/api/v1/settings/discover/add', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: Number(values.sliderType),
|
||||
title: values.title,
|
||||
data: values.data,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
|
||||
addToast(
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
} from '@heroicons/react/24/solid';
|
||||
import { DiscoverSliderType } from '@server/constants/discover';
|
||||
import type DiscoverSlider from '@server/entity/DiscoverSlider';
|
||||
import axios from 'axios';
|
||||
import { useRef, useState } from 'react';
|
||||
import { useDrag, useDrop } from 'react-aria';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -78,7 +77,10 @@ const DiscoverSliderEdit = ({
|
||||
|
||||
const deleteSlider = async () => {
|
||||
try {
|
||||
await axios.delete(`/api/v1/settings/discover/${slider.id}`);
|
||||
const res = await fetch(`/api/v1/settings/discover/${slider.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.deletesuccess), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
} from '@heroicons/react/24/solid';
|
||||
import { DiscoverSliderType } from '@server/constants/discover';
|
||||
import type DiscoverSlider from '@server/entity/DiscoverSlider';
|
||||
import axios from 'axios';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -76,7 +75,14 @@ const Discover = () => {
|
||||
|
||||
const updateSliders = async () => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/discover', sliders);
|
||||
const res = await fetch('/api/v1/settings/discover', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(sliders),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.updatesuccess), {
|
||||
appearance: 'success',
|
||||
@@ -94,7 +100,10 @@ const Discover = () => {
|
||||
|
||||
const resetSliders = async () => {
|
||||
try {
|
||||
await axios.get('/api/v1/settings/discover/reset');
|
||||
const res = await fetch('/api/v1/settings/discover/reset', {
|
||||
method: 'GET',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.resetsuccess), {
|
||||
appearance: 'success',
|
||||
|
||||
@@ -5,7 +5,6 @@ import defineMessages from '@app/utils/defineMessages';
|
||||
import { Menu, Transition } from '@headlessui/react';
|
||||
import { EllipsisVerticalIcon } from '@heroicons/react/24/solid';
|
||||
import type { default as IssueCommentType } from '@server/entity/IssueComment';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
@@ -49,7 +48,10 @@ const IssueComment = ({
|
||||
|
||||
const deleteComment = async () => {
|
||||
try {
|
||||
await axios.delete(`/api/v1/issueComment/${comment.id}`);
|
||||
const res = await fetch(`/api/v1/issueComment/${comment.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
} catch (e) {
|
||||
// something went wrong deleting the comment
|
||||
} finally {
|
||||
@@ -175,9 +177,14 @@ const IssueComment = ({
|
||||
<Formik
|
||||
initialValues={{ newMessage: comment.message }}
|
||||
onSubmit={async (values) => {
|
||||
await axios.put(`/api/v1/issueComment/${comment.id}`, {
|
||||
message: values.newMessage,
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/issueComment/${comment.id}`,
|
||||
{
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ message: values.newMessage }),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (onUpdate) {
|
||||
onUpdate();
|
||||
|
||||
@@ -11,7 +11,7 @@ import useDeepLinks from '@app/hooks/useDeepLinks';
|
||||
import useSettings from '@app/hooks/useSettings';
|
||||
import { Permission, useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import Error from '@app/pages/_error';
|
||||
import ErrorPage from '@app/pages/_error';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import {
|
||||
@@ -27,7 +27,6 @@ import { MediaServerType } from '@server/constants/server';
|
||||
import type Issue from '@server/entity/Issue';
|
||||
import type { MovieDetails } from '@server/models/Movie';
|
||||
import type { TvDetails } from '@server/models/Tv';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import getConfig from 'next/config';
|
||||
import Image from 'next/image';
|
||||
@@ -116,7 +115,7 @@ const IssueDetails = () => {
|
||||
}
|
||||
|
||||
if (!data || !issueData) {
|
||||
return <Error statusCode={404} />;
|
||||
return <ErrorPage statusCode={404} />;
|
||||
}
|
||||
|
||||
const belongsToUser = issueData.createdBy.id === currentUser?.id;
|
||||
@@ -125,9 +124,11 @@ const IssueDetails = () => {
|
||||
|
||||
const editFirstComment = async (newMessage: string) => {
|
||||
try {
|
||||
await axios.put(`/api/v1/issueComment/${firstComment.id}`, {
|
||||
message: newMessage,
|
||||
const res = await fetch(`/api/v1/issueComment/${firstComment.id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ message: newMessage }),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.toasteditdescriptionsuccess), {
|
||||
appearance: 'success',
|
||||
@@ -144,7 +145,10 @@ const IssueDetails = () => {
|
||||
|
||||
const updateIssueStatus = async (newStatus: 'open' | 'resolved') => {
|
||||
try {
|
||||
await axios.post(`/api/v1/issue/${issueData.id}/${newStatus}`);
|
||||
const res = await fetch(`/api/v1/issue/${issueData.id}/${newStatus}`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.toaststatusupdated), {
|
||||
appearance: 'success',
|
||||
@@ -161,7 +165,10 @@ const IssueDetails = () => {
|
||||
|
||||
const deleteIssue = async () => {
|
||||
try {
|
||||
await axios.delete(`/api/v1/issue/${issueData.id}`);
|
||||
const res = await fetch(`/api/v1/issue/${issueData.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.toastissuedeleted), {
|
||||
appearance: 'success',
|
||||
@@ -490,9 +497,14 @@ const IssueDetails = () => {
|
||||
}}
|
||||
validationSchema={CommentSchema}
|
||||
onSubmit={async (values, { resetForm }) => {
|
||||
await axios.post(`/api/v1/issue/${issueData?.id}/comment`, {
|
||||
message: values.message,
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/issue/${issueData?.id}/comment`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ message: values.message }),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
revalidateIssue();
|
||||
resetForm();
|
||||
}}
|
||||
|
||||
@@ -11,7 +11,6 @@ import { MediaStatus } from '@server/constants/media';
|
||||
import type Issue from '@server/entity/Issue';
|
||||
import type { MovieDetails } from '@server/models/Movie';
|
||||
import type { TvDetails } from '@server/models/Tv';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import Link from 'next/link';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -101,14 +100,19 @@ const CreateIssueModal = ({
|
||||
validationSchema={CreateIssueModalSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
const newIssue = await axios.post<Issue>('/api/v1/issue', {
|
||||
issueType: values.selectedIssue.issueType,
|
||||
message: values.message,
|
||||
mediaId: data?.mediaInfo?.id,
|
||||
problemSeason: values.problemSeason,
|
||||
problemEpisode:
|
||||
values.problemSeason > 0 ? values.problemEpisode : 0,
|
||||
const res = await fetch('/api/v1/issue', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
issueType: values.selectedIssue.issueType,
|
||||
message: values.message,
|
||||
mediaId: data?.mediaInfo?.id,
|
||||
problemSeason: values.problemSeason,
|
||||
problemEpisode:
|
||||
values.problemSeason > 0 ? values.problemEpisode : 0,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const newIssue: Issue = await res.json();
|
||||
|
||||
if (data) {
|
||||
addToast(
|
||||
@@ -119,7 +123,7 @@ const CreateIssueModal = ({
|
||||
strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
|
||||
})}
|
||||
</div>
|
||||
<Link href={`/issues/${newIssue.data.id}`} legacyBehavior>
|
||||
<Link href={`/issues/${newIssue.id}`} legacyBehavior>
|
||||
<Button as="a" className="mt-4">
|
||||
<span>{intl.formatMessage(messages.toastviewissue)}</span>
|
||||
<ArrowRightCircleIcon />
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
ClockIcon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
import { CogIcon, UserIcon } from '@heroicons/react/24/solid';
|
||||
import axios from 'axios';
|
||||
import Image from 'next/image';
|
||||
import type { LinkProps } from 'next/link';
|
||||
import Link from 'next/link';
|
||||
@@ -39,9 +38,13 @@ const UserDropdown = () => {
|
||||
const { user, revalidate } = useUser();
|
||||
|
||||
const logout = async () => {
|
||||
const response = await axios.post('/api/v1/auth/logout');
|
||||
const res = await fetch('/api/v1/auth/logout', {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
if (response.data?.status === 'ok') {
|
||||
if (data?.status === 'ok') {
|
||||
revalidate();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@ import Modal from '@app/components/Common/Modal';
|
||||
import useSettings from '@app/hooks/useSettings';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { useIntl } from 'react-intl';
|
||||
import * as Yup from 'yup';
|
||||
@@ -58,11 +57,15 @@ const AddEmailModal: React.FC<AddEmailModalProps> = ({
|
||||
validationSchema={EmailSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/auth/jellyfin', {
|
||||
username: username,
|
||||
password: password,
|
||||
email: values.email,
|
||||
const res = await fetch('/api/v1/auth/jellyfin', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: password,
|
||||
email: values.email,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
onSave();
|
||||
} catch (e) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import useSettings from '@app/hooks/useSettings';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { InformationCircleIcon } from '@heroicons/react/24/solid';
|
||||
import { ApiErrorCode } from '@server/constants/error';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import getConfig from 'next/config';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -105,15 +104,22 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
|
||||
validationSchema={LoginSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/auth/jellyfin', {
|
||||
username: values.username,
|
||||
password: values.password,
|
||||
hostname: values.hostname,
|
||||
port: values.port,
|
||||
useSsl: values.useSsl,
|
||||
urlBase: values.urlBase,
|
||||
email: values.email,
|
||||
const res = await fetch('/api/v1/auth/jellyfin', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: values.username,
|
||||
password: values.password,
|
||||
hostname: values.hostname,
|
||||
port: values.port,
|
||||
useSsl: values.useSsl,
|
||||
urlBase: values.urlBase,
|
||||
email: values.email,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
} catch (e) {
|
||||
let errorMessage = null;
|
||||
switch (e.response?.data?.message) {
|
||||
@@ -339,11 +345,18 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
|
||||
validationSchema={LoginSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/auth/jellyfin', {
|
||||
username: values.username,
|
||||
password: values.password,
|
||||
email: values.username,
|
||||
const res = await fetch('/api/v1/auth/jellyfin', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: values.username,
|
||||
password: values.password,
|
||||
email: values.username,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
} catch (e) {
|
||||
toasts.addToast(
|
||||
intl.formatMessage(
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
ArrowLeftOnRectangleIcon,
|
||||
LifebuoyIcon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
@@ -56,10 +55,17 @@ const LocalLogin = ({ revalidate }: LocalLoginProps) => {
|
||||
validationSchema={LoginSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/auth/local', {
|
||||
email: values.email,
|
||||
password: values.password,
|
||||
const res = await fetch('/api/v1/auth/local', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: values.email,
|
||||
password: values.password,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
} catch (e) {
|
||||
setLoginError(intl.formatMessage(messages.loginerror));
|
||||
} finally {
|
||||
|
||||
@@ -10,7 +10,6 @@ import defineMessages from '@app/utils/defineMessages';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import { XCircleIcon } from '@heroicons/react/24/solid';
|
||||
import { MediaServerType } from '@server/constants/server';
|
||||
import axios from 'axios';
|
||||
import getConfig from 'next/config';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import Image from 'next/image';
|
||||
@@ -44,9 +43,14 @@ const Login = () => {
|
||||
const login = async () => {
|
||||
setProcessing(true);
|
||||
try {
|
||||
const response = await axios.post('/api/v1/auth/plex', { authToken });
|
||||
const res = await fetch('/api/v1/auth/plex', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ authToken }),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
if (response.data?.id) {
|
||||
if (data?.id) {
|
||||
revalidate();
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import type { MediaWatchDataResponse } from '@server/interfaces/api/mediaInterfa
|
||||
import type { RadarrSettings, SonarrSettings } from '@server/lib/settings';
|
||||
import type { MovieDetails } from '@server/models/Movie';
|
||||
import type { TvDetails } from '@server/models/Tv';
|
||||
import axios from 'axios';
|
||||
import getConfig from 'next/config';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
@@ -113,15 +112,26 @@ const ManageSlideOver = ({
|
||||
|
||||
const deleteMedia = async () => {
|
||||
if (data.mediaInfo) {
|
||||
await axios.delete(`/api/v1/media/${data.mediaInfo.id}`);
|
||||
const res = await fetch(`/api/v1/media/${data.mediaInfo.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
revalidate();
|
||||
}
|
||||
};
|
||||
|
||||
const deleteMediaFile = async () => {
|
||||
if (data.mediaInfo) {
|
||||
await axios.delete(`/api/v1/media/${data.mediaInfo.id}/file`);
|
||||
await axios.delete(`/api/v1/media/${data.mediaInfo.id}`);
|
||||
const res1 = await fetch(`/api/v1/media/${data.mediaInfo.id}/file`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res1.ok) throw new Error();
|
||||
|
||||
const res2 = await fetch(`/api/v1/media/${data.mediaInfo.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res2.ok) throw new Error();
|
||||
|
||||
revalidate();
|
||||
}
|
||||
};
|
||||
@@ -149,9 +159,16 @@ const ManageSlideOver = ({
|
||||
|
||||
const markAvailable = async (is4k = false) => {
|
||||
if (data.mediaInfo) {
|
||||
await axios.post(`/api/v1/media/${data.mediaInfo?.id}/available`, {
|
||||
is4k,
|
||||
const res = await fetch(`/api/v1/media/${data.mediaInfo?.id}/available`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
is4k,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
revalidate();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
} from '@heroicons/react/24/solid';
|
||||
import { MediaRequestStatus } from '@server/constants/media';
|
||||
import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import axios from 'axios';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -53,7 +52,10 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
||||
|
||||
const updateRequest = async (type: 'approve' | 'decline'): Promise<void> => {
|
||||
setIsUpdating(true);
|
||||
await axios.post(`/api/v1/request/${request.id}/${type}`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}/${type}`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (onUpdate) {
|
||||
onUpdate();
|
||||
@@ -63,7 +65,10 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
||||
|
||||
const deleteRequest = async () => {
|
||||
setIsUpdating(true);
|
||||
await axios.delete(`/api/v1/request/${request.id}`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (onUpdate) {
|
||||
onUpdate();
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
import { MediaRequestStatus, MediaStatus } from '@server/constants/media';
|
||||
import type Media from '@server/entity/Media';
|
||||
import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import axios from 'axios';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
@@ -94,9 +93,13 @@ const RequestButton = ({
|
||||
request: MediaRequest,
|
||||
type: 'approve' | 'decline'
|
||||
) => {
|
||||
const response = await axios.post(`/api/v1/request/${request.id}/${type}`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}/${type}`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
if (response) {
|
||||
if (data) {
|
||||
onUpdate();
|
||||
}
|
||||
};
|
||||
@@ -111,7 +114,11 @@ const RequestButton = ({
|
||||
|
||||
await Promise.all(
|
||||
requests.map(async (request) => {
|
||||
return axios.post(`/api/v1/request/${request.id}/${type}`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}/${type}`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
return res.json();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import { MediaRequestStatus } from '@server/constants/media';
|
||||
import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import type { MovieDetails } from '@server/models/Movie';
|
||||
import type { TvDetails } from '@server/models/Tv';
|
||||
import axios from 'axios';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -74,7 +73,10 @@ const RequestCardError = ({ requestData }: RequestCardErrorProps) => {
|
||||
});
|
||||
|
||||
const deleteRequest = async () => {
|
||||
await axios.delete(`/api/v1/media/${requestData?.media.id}`);
|
||||
const res = await fetch(`/api/v1/media/${requestData?.media.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/media?filter=allavailable&take=20&sort=mediaAdded');
|
||||
mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');
|
||||
};
|
||||
@@ -255,15 +257,22 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
||||
});
|
||||
|
||||
const modifyRequest = async (type: 'approve' | 'decline') => {
|
||||
const response = await axios.post(`/api/v1/request/${request.id}/${type}`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}/${type}`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
if (response) {
|
||||
if (data) {
|
||||
revalidate();
|
||||
}
|
||||
};
|
||||
|
||||
const deleteRequest = async () => {
|
||||
await axios.delete(`/api/v1/request/${request.id}`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');
|
||||
};
|
||||
|
||||
@@ -271,9 +280,13 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
||||
setRetrying(true);
|
||||
|
||||
try {
|
||||
const response = await axios.post(`/api/v1/request/${request.id}/retry`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}/retry`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
if (response) {
|
||||
if (data) {
|
||||
revalidate();
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import { MediaRequestStatus } from '@server/constants/media';
|
||||
import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import type { MovieDetails } from '@server/models/Movie';
|
||||
import type { TvDetails } from '@server/models/Tv';
|
||||
import axios from 'axios';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
@@ -62,7 +61,10 @@ const RequestItemError = ({
|
||||
const { hasPermission } = useUser();
|
||||
|
||||
const deleteRequest = async () => {
|
||||
await axios.delete(`/api/v1/media/${requestData?.media.id}`);
|
||||
const res = await fetch(`/api/v1/media/${requestData?.media.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
revalidateList();
|
||||
};
|
||||
|
||||
@@ -319,15 +321,22 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
||||
const [isRetrying, setRetrying] = useState(false);
|
||||
|
||||
const modifyRequest = async (type: 'approve' | 'decline') => {
|
||||
const response = await axios.post(`/api/v1/request/${request.id}/${type}`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}/${type}`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
if (response) {
|
||||
if (data) {
|
||||
revalidate();
|
||||
}
|
||||
};
|
||||
|
||||
const deleteRequest = async () => {
|
||||
await axios.delete(`/api/v1/request/${request.id}`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
revalidateList();
|
||||
};
|
||||
@@ -336,7 +345,12 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
||||
setRetrying(true);
|
||||
|
||||
try {
|
||||
const result = await axios.post(`/api/v1/request/${request.id}/retry`);
|
||||
const res = await fetch(`/api/v1/request/${request.id}/retry`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const result = await res.json();
|
||||
|
||||
revalidate(result.data);
|
||||
} catch (e) {
|
||||
addToast(intl.formatMessage(messages.failedretry), {
|
||||
|
||||
@@ -13,7 +13,6 @@ import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import type { QuotaResponse } from '@server/interfaces/api/userInterfaces';
|
||||
import { Permission } from '@server/lib/permissions';
|
||||
import type { Collection } from '@server/models/Collection';
|
||||
import axios from 'axios';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -197,12 +196,19 @@ const CollectionRequestModal = ({
|
||||
(
|
||||
data?.parts.filter((part) => selectedParts.includes(part.id)) ?? []
|
||||
).map(async (part) => {
|
||||
await axios.post<MediaRequest>('/api/v1/request', {
|
||||
mediaId: part.id,
|
||||
mediaType: 'movie',
|
||||
is4k,
|
||||
...overrideParams,
|
||||
const res = await fetch('/api/v1/request', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mediaId: part.id,
|
||||
mediaType: 'movie',
|
||||
is4k,
|
||||
...overrideParams,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import type { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import type { QuotaResponse } from '@server/interfaces/api/userInterfaces';
|
||||
import { Permission } from '@server/lib/permissions';
|
||||
import type { MovieDetails } from '@server/models/Movie';
|
||||
import axios from 'axios';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -89,15 +88,23 @@ const MovieRequestModal = ({
|
||||
tags: requestOverrides.tags,
|
||||
};
|
||||
}
|
||||
const response = await axios.post<MediaRequest>('/api/v1/request', {
|
||||
mediaId: data?.id,
|
||||
mediaType: 'movie',
|
||||
is4k,
|
||||
...overrideParams,
|
||||
const res = await fetch('/api/v1/request', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mediaId: data?.id,
|
||||
mediaType: 'movie',
|
||||
is4k,
|
||||
...overrideParams,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const mediaRequest: MediaRequest = await res.json();
|
||||
mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');
|
||||
|
||||
if (response.data) {
|
||||
if (mediaRequest) {
|
||||
if (onComplete) {
|
||||
onComplete(
|
||||
hasPermission(
|
||||
@@ -136,12 +143,14 @@ const MovieRequestModal = ({
|
||||
setIsUpdating(true);
|
||||
|
||||
try {
|
||||
const response = await axios.delete<MediaRequest>(
|
||||
`/api/v1/request/${editRequest?.id}`
|
||||
);
|
||||
const res = await fetch(`/api/v1/request/${editRequest?.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');
|
||||
|
||||
if (response.status === 204) {
|
||||
if (res.status === 204) {
|
||||
if (onComplete) {
|
||||
onComplete(MediaStatus.UNKNOWN);
|
||||
}
|
||||
@@ -164,17 +173,27 @@ const MovieRequestModal = ({
|
||||
setIsUpdating(true);
|
||||
|
||||
try {
|
||||
await axios.put(`/api/v1/request/${editRequest?.id}`, {
|
||||
mediaType: 'movie',
|
||||
serverId: requestOverrides?.server,
|
||||
profileId: requestOverrides?.profile,
|
||||
rootFolder: requestOverrides?.folder,
|
||||
userId: requestOverrides?.user?.id,
|
||||
tags: requestOverrides?.tags,
|
||||
const res = await fetch(`/api/v1/request/${editRequest?.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mediaType: 'movie',
|
||||
serverId: requestOverrides?.server,
|
||||
profileId: requestOverrides?.profile,
|
||||
rootFolder: requestOverrides?.folder,
|
||||
userId: requestOverrides?.user?.id,
|
||||
tags: requestOverrides?.tags,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (alsoApproveRequest) {
|
||||
await axios.post(`/api/v1/request/${editRequest?.id}/approve`);
|
||||
const res = await fetch(`/api/v1/request/${editRequest?.id}/approve`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import type SeasonRequest from '@server/entity/SeasonRequest';
|
||||
import type { QuotaResponse } from '@server/interfaces/api/userInterfaces';
|
||||
import { Permission } from '@server/lib/permissions';
|
||||
import type { TvDetails } from '@server/models/Tv';
|
||||
import axios from 'axios';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -111,22 +110,35 @@ const TvRequestModal = ({
|
||||
|
||||
try {
|
||||
if (selectedSeasons.length > 0) {
|
||||
await axios.put(`/api/v1/request/${editRequest.id}`, {
|
||||
mediaType: 'tv',
|
||||
serverId: requestOverrides?.server,
|
||||
profileId: requestOverrides?.profile,
|
||||
rootFolder: requestOverrides?.folder,
|
||||
languageProfileId: requestOverrides?.language,
|
||||
userId: requestOverrides?.user?.id,
|
||||
tags: requestOverrides?.tags,
|
||||
seasons: selectedSeasons,
|
||||
const res = await fetch(`/api/v1/request/${editRequest.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mediaType: 'tv',
|
||||
serverId: requestOverrides?.server,
|
||||
profileId: requestOverrides?.profile,
|
||||
rootFolder: requestOverrides?.folder,
|
||||
languageProfileId: requestOverrides?.language,
|
||||
userId: requestOverrides?.user?.id,
|
||||
tags: requestOverrides?.tags,
|
||||
seasons: selectedSeasons,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (alsoApproveRequest) {
|
||||
await axios.post(`/api/v1/request/${editRequest.id}/approve`);
|
||||
const res = await fetch(`/api/v1/request/${editRequest.id}/approve`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
} else {
|
||||
await axios.delete(`/api/v1/request/${editRequest.id}`);
|
||||
const res = await fetch(`/api/v1/request/${editRequest.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');
|
||||
|
||||
@@ -191,23 +203,32 @@ const TvRequestModal = ({
|
||||
tags: requestOverrides.tags,
|
||||
};
|
||||
}
|
||||
const response = await axios.post<MediaRequest>('/api/v1/request', {
|
||||
mediaId: data?.id,
|
||||
tvdbId: tvdbId ?? data?.externalIds.tvdbId,
|
||||
mediaType: 'tv',
|
||||
is4k,
|
||||
seasons: settings.currentSettings.partialRequestsEnabled
|
||||
? selectedSeasons
|
||||
: getAllSeasons().filter(
|
||||
(season) => !getAllRequestedSeasons().includes(season)
|
||||
),
|
||||
...overrideParams,
|
||||
const res = await fetch('/api/v1/request', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mediaId: data?.id,
|
||||
tvdbId: tvdbId ?? data?.externalIds.tvdbId,
|
||||
mediaType: 'tv',
|
||||
is4k,
|
||||
seasons: settings.currentSettings.partialRequestsEnabled
|
||||
? selectedSeasons
|
||||
: getAllSeasons().filter(
|
||||
(season) => !getAllRequestedSeasons().includes(season)
|
||||
),
|
||||
...overrideParams,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const mediaRequest: MediaRequest = await res.json();
|
||||
|
||||
mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');
|
||||
|
||||
if (response.data) {
|
||||
if (mediaRequest) {
|
||||
if (onComplete) {
|
||||
onComplete(response.data.media.status);
|
||||
onComplete(mediaRequest.media.status);
|
||||
}
|
||||
addToast(
|
||||
<span>
|
||||
|
||||
@@ -4,7 +4,6 @@ import PageTitle from '@app/components/Common/PageTitle';
|
||||
import LanguagePicker from '@app/components/Layout/LanguagePicker';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowLeftIcon, EnvelopeIcon } from '@heroicons/react/24/solid';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
@@ -85,14 +84,18 @@ const ResetPassword = () => {
|
||||
}}
|
||||
validationSchema={ResetSchema}
|
||||
onSubmit={async (values) => {
|
||||
const response = await axios.post(
|
||||
`/api/v1/auth/reset-password`,
|
||||
{
|
||||
const res = await fetch(`/api/v1/auth/reset-password`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: values.email,
|
||||
}
|
||||
);
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (response.status === 200) {
|
||||
if (res.status === 200) {
|
||||
setSubmitted(true);
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -5,7 +5,6 @@ import LanguagePicker from '@app/components/Layout/LanguagePicker';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { LifebuoyIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Form, Formik } from 'formik';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
@@ -100,14 +99,21 @@ const ResetPassword = () => {
|
||||
}}
|
||||
validationSchema={ResetSchema}
|
||||
onSubmit={async (values) => {
|
||||
const response = await axios.post(
|
||||
const res = await fetch(
|
||||
`/api/v1/auth/reset-password/${guid}`,
|
||||
{
|
||||
password: values.password,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
password: values.password,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (response.status === 200) {
|
||||
if (res.status === 200) {
|
||||
setSubmitted(true);
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -18,7 +18,6 @@ import type {
|
||||
ProductionCompany,
|
||||
WatchProviderDetails,
|
||||
} from '@server/models/common';
|
||||
import axios from 'axios';
|
||||
import { orderBy } from 'lodash';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -69,11 +68,9 @@ export const CompanySelector = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await axios.get<ProductionCompany>(
|
||||
`/api/v1/studio/${defaultValue}`
|
||||
);
|
||||
|
||||
const studio = response.data;
|
||||
const res = await fetch(`/api/v1/studio/${defaultValue}`);
|
||||
if (!res.ok) throw new Error();
|
||||
const studio: ProductionCompany = await res.json();
|
||||
|
||||
setDefaultDataValue([
|
||||
{
|
||||
@@ -91,16 +88,15 @@ export const CompanySelector = ({
|
||||
return [];
|
||||
}
|
||||
|
||||
const results = await axios.get<TmdbCompanySearchResponse>(
|
||||
'/api/v1/search/company',
|
||||
{
|
||||
params: {
|
||||
query: encodeURIExtraParams(inputValue),
|
||||
},
|
||||
}
|
||||
const res = await fetch(
|
||||
`/api/v1/search/company?query=${encodeURIExtraParams(inputValue)}`
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const results: TmdbCompanySearchResponse = await res.json();
|
||||
|
||||
return results.data.results.map((result) => ({
|
||||
return results.results.map((result) => ({
|
||||
label: result.name,
|
||||
value: result.id,
|
||||
}));
|
||||
@@ -154,11 +150,15 @@ export const GenreSelector = ({
|
||||
|
||||
const genres = defaultValue.split(',');
|
||||
|
||||
const response = await axios.get<TmdbGenre[]>(`/api/v1/genres/${type}`);
|
||||
const res = await fetch(`/api/v1/genres/${type}`);
|
||||
if (!res.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const response: TmdbGenre[] = await res.json();
|
||||
|
||||
const genreData = genres
|
||||
.filter((genre) => response.data.find((gd) => gd.id === Number(genre)))
|
||||
.map((g) => response.data.find((gd) => gd.id === Number(g)))
|
||||
.filter((genre) => response.find((gd) => gd.id === Number(genre)))
|
||||
.map((g) => response.find((gd) => gd.id === Number(g)))
|
||||
.map((g) => ({
|
||||
label: g?.name ?? '',
|
||||
value: g?.id ?? 0,
|
||||
@@ -171,11 +171,11 @@ export const GenreSelector = ({
|
||||
}, [defaultValue, type]);
|
||||
|
||||
const loadGenreOptions = async (inputValue: string) => {
|
||||
const results = await axios.get<GenreSliderItem[]>(
|
||||
`/api/v1/discover/genreslider/${type}`
|
||||
);
|
||||
const res = await fetch(`/api/v1/discover/genreslider/${type}`);
|
||||
if (!res.ok) throw new Error();
|
||||
const results: GenreSliderItem[] = await res.json();
|
||||
|
||||
return results.data
|
||||
return results
|
||||
.map((result) => ({
|
||||
label: result.name,
|
||||
value: result.id,
|
||||
@@ -222,11 +222,13 @@ export const KeywordSelector = ({
|
||||
|
||||
const keywords = await Promise.all(
|
||||
defaultValue.split(',').map(async (keywordId) => {
|
||||
const keyword = await axios.get<Keyword>(
|
||||
`/api/v1/keyword/${keywordId}`
|
||||
);
|
||||
const res = await fetch(`/api/v1/keyword/${keywordId}`);
|
||||
if (!res.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const keyword: Keyword = await res.json();
|
||||
|
||||
return keyword.data;
|
||||
return keyword;
|
||||
})
|
||||
);
|
||||
|
||||
@@ -242,16 +244,15 @@ export const KeywordSelector = ({
|
||||
}, [defaultValue]);
|
||||
|
||||
const loadKeywordOptions = async (inputValue: string) => {
|
||||
const results = await axios.get<TmdbKeywordSearchResponse>(
|
||||
'/api/v1/search/keyword',
|
||||
{
|
||||
params: {
|
||||
query: encodeURIExtraParams(inputValue),
|
||||
},
|
||||
}
|
||||
const res = await fetch(
|
||||
`/api/v1/search/keyword?query=${encodeURIExtraParams(inputValue)}`
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const results: TmdbKeywordSearchResponse = await res.json();
|
||||
|
||||
return results.data.results.map((result) => ({
|
||||
return results.results.map((result) => ({
|
||||
label: result.name,
|
||||
value: result.id,
|
||||
}));
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable no-console */
|
||||
import useSettings from '@app/hooks/useSettings';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import axios from 'axios';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const ServiceWorkerSetup = () => {
|
||||
@@ -26,11 +25,18 @@ const ServiceWorkerSetup = () => {
|
||||
const parsedSub = JSON.parse(JSON.stringify(sub));
|
||||
|
||||
if (parsedSub.keys.p256dh && parsedSub.keys.auth) {
|
||||
await axios.post('/api/v1/user/registerPushSubscription', {
|
||||
endpoint: parsedSub.endpoint,
|
||||
p256dh: parsedSub.keys.p256dh,
|
||||
auth: parsedSub.keys.auth,
|
||||
const res = await fetch('/api/v1/user/registerPushSubscription', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
endpoint: parsedSub.endpoint,
|
||||
p256dh: parsedSub.keys.p256dh,
|
||||
auth: parsedSub.keys.auth,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -5,7 +5,6 @@ import useSettings from '@app/hooks/useSettings';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -73,16 +72,23 @@ const NotificationsDiscord = () => {
|
||||
validationSchema={NotificationsDiscordSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/discord', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
botUsername: values.botUsername,
|
||||
botAvatarUrl: values.botAvatarUrl,
|
||||
webhookUrl: values.webhookUrl,
|
||||
enableMentions: values.enableMentions,
|
||||
const res = await fetch('/api/v1/settings/notifications/discord', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
botUsername: values.botUsername,
|
||||
botAvatarUrl: values.botAvatarUrl,
|
||||
webhookUrl: values.webhookUrl,
|
||||
enableMentions: values.enableMentions,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.discordsettingssaved), {
|
||||
appearance: 'success',
|
||||
@@ -121,16 +127,26 @@ const NotificationsDiscord = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/discord/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
botUsername: values.botUsername,
|
||||
botAvatarUrl: values.botAvatarUrl,
|
||||
webhookUrl: values.webhookUrl,
|
||||
enableMentions: values.enableMentions,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/discord/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
botUsername: values.botUsername,
|
||||
botAvatarUrl: values.botAvatarUrl,
|
||||
webhookUrl: values.webhookUrl,
|
||||
enableMentions: values.enableMentions,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -5,7 +5,6 @@ import SettingsBadge from '@app/components/Settings/SettingsBadge';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -148,24 +147,31 @@ const NotificationsEmail = () => {
|
||||
validationSchema={NotificationsEmailSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/email', {
|
||||
enabled: values.enabled,
|
||||
options: {
|
||||
userEmailRequired: values.userEmailRequired,
|
||||
emailFrom: values.emailFrom,
|
||||
smtpHost: values.smtpHost,
|
||||
smtpPort: Number(values.smtpPort),
|
||||
secure: values.encryption === 'implicit',
|
||||
ignoreTls: values.encryption === 'none',
|
||||
requireTls: values.encryption === 'opportunistic',
|
||||
authUser: values.authUser,
|
||||
authPass: values.authPass,
|
||||
allowSelfSigned: values.allowSelfSigned,
|
||||
senderName: values.senderName,
|
||||
pgpPrivateKey: values.pgpPrivateKey,
|
||||
pgpPassword: values.pgpPassword,
|
||||
const res = await fetch('/api/v1/settings/notifications/email', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
options: {
|
||||
userEmailRequired: values.userEmailRequired,
|
||||
emailFrom: values.emailFrom,
|
||||
smtpHost: values.smtpHost,
|
||||
smtpPort: Number(values.smtpPort),
|
||||
secure: values.encryption === 'implicit',
|
||||
ignoreTls: values.encryption === 'none',
|
||||
requireTls: values.encryption === 'opportunistic',
|
||||
authUser: values.authUser,
|
||||
authPass: values.authPass,
|
||||
allowSelfSigned: values.allowSelfSigned,
|
||||
senderName: values.senderName,
|
||||
pgpPrivateKey: values.pgpPrivateKey,
|
||||
pgpPassword: values.pgpPassword,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
|
||||
addToast(intl.formatMessage(messages.emailsettingssaved), {
|
||||
@@ -197,22 +203,32 @@ const NotificationsEmail = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/email/test', {
|
||||
enabled: true,
|
||||
options: {
|
||||
emailFrom: values.emailFrom,
|
||||
smtpHost: values.smtpHost,
|
||||
smtpPort: Number(values.smtpPort),
|
||||
secure: values.encryption === 'implicit',
|
||||
ignoreTls: values.encryption === 'none',
|
||||
requireTls: values.encryption === 'opportunistic',
|
||||
authUser: values.authUser,
|
||||
authPass: values.authPass,
|
||||
senderName: values.senderName,
|
||||
pgpPrivateKey: values.pgpPrivateKey,
|
||||
pgpPassword: values.pgpPassword,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/email/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
options: {
|
||||
emailFrom: values.emailFrom,
|
||||
smtpHost: values.smtpHost,
|
||||
smtpPort: Number(values.smtpPort),
|
||||
secure: values.encryption === 'implicit',
|
||||
ignoreTls: values.encryption === 'none',
|
||||
requireTls: values.encryption === 'opportunistic',
|
||||
authUser: values.authUser,
|
||||
authPass: values.authPass,
|
||||
senderName: values.senderName,
|
||||
pgpPrivateKey: values.pgpPrivateKey,
|
||||
pgpPassword: values.pgpPassword,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -4,7 +4,6 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/solid';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -83,14 +82,21 @@ const NotificationsGotify = () => {
|
||||
validationSchema={NotificationsGotifySchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/gotify', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
url: values.url,
|
||||
token: values.token,
|
||||
const res = await fetch('/api/v1/settings/notifications/gotify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
url: values.url,
|
||||
token: values.token,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.gotifysettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -128,14 +134,24 @@ const NotificationsGotify = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/gotify/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
url: values.url,
|
||||
token: values.token,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/gotify/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
url: values.url,
|
||||
token: values.token,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -4,7 +4,6 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -69,14 +68,21 @@ const NotificationsLunaSea = () => {
|
||||
validationSchema={NotificationsLunaSeaSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/lunasea', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
profileName: values.profileName,
|
||||
const res = await fetch('/api/v1/settings/notifications/lunasea', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
profileName: values.profileName,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.settingsSaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -114,14 +120,24 @@ const NotificationsLunaSea = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/lunasea/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
profileName: values.profileName,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/lunasea/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
profileName: values.profileName,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -5,7 +5,6 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -68,14 +67,21 @@ const NotificationsPushbullet = () => {
|
||||
validationSchema={NotificationsPushbulletSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/pushbullet', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
channelTag: values.channelTag,
|
||||
const res = await fetch('/api/v1/settings/notifications/pushbullet', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
channelTag: values.channelTag,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.pushbulletSettingsSaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -113,14 +119,24 @@ const NotificationsPushbullet = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/pushbullet/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
channelTag: values.channelTag,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/pushbullet/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
channelTag: values.channelTag,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -5,7 +5,6 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import type { PushoverSound } from '@server/api/pushover';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -94,14 +93,21 @@ const NotificationsPushover = () => {
|
||||
validationSchema={NotificationsPushoverSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/pushover', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
const res = await fetch('/api/v1/settings/notifications/pushover', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.pushoversettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -139,16 +145,25 @@ const NotificationsPushover = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/pushover/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
sound: values.sound,
|
||||
},
|
||||
});
|
||||
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/pushover/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
accessToken: values.accessToken,
|
||||
userToken: values.userToken,
|
||||
sound: values.sound,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -65,13 +64,20 @@ const NotificationsSlack = () => {
|
||||
validationSchema={NotificationsSlackSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/slack', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
const res = await fetch('/api/v1/settings/notifications/slack', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.slacksettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -109,13 +115,23 @@ const NotificationsSlack = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/slack/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/slack/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -5,7 +5,6 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -84,16 +83,23 @@ const NotificationsTelegram = () => {
|
||||
validationSchema={NotificationsTelegramSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/telegram', {
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
const res = await fetch('/api/v1/settings/notifications/telegram', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.telegramsettingssaved), {
|
||||
appearance: 'success',
|
||||
@@ -132,16 +138,26 @@ const NotificationsTelegram = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/telegram/test', {
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/telegram/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
botAPI: values.botAPI,
|
||||
chatId: values.chatId,
|
||||
sendSilently: values.sendSilently,
|
||||
botUsername: values.botUsername,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -4,7 +4,6 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -58,10 +57,17 @@ const NotificationsWebPush = () => {
|
||||
}}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/notifications/webpush', {
|
||||
enabled: values.enabled,
|
||||
options: {},
|
||||
const res = await fetch('/api/v1/settings/notifications/webpush', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
options: {},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
addToast(intl.formatMessage(messages.webpushsettingssaved), {
|
||||
appearance: 'success',
|
||||
@@ -92,10 +98,20 @@ const NotificationsWebPush = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/notifications/webpush/test', {
|
||||
enabled: true,
|
||||
options: {},
|
||||
});
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/webpush/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
options: {},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
ArrowPathIcon,
|
||||
QuestionMarkCircleIcon,
|
||||
} from '@heroicons/react/24/solid';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import dynamic from 'next/dynamic';
|
||||
import Link from 'next/link';
|
||||
@@ -150,15 +149,22 @@ const NotificationsWebhook = () => {
|
||||
validationSchema={NotificationsWebhookSchema}
|
||||
onSubmit={async (values) => {
|
||||
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,
|
||||
const res = await fetch('/api/v1/settings/notifications/webhook', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: values.enabled,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
jsonPayload: JSON.stringify(values.jsonPayload),
|
||||
authHeader: values.authHeader,
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.webhooksettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
@@ -207,16 +213,25 @@ const NotificationsWebhook = () => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
const res = await fetch(
|
||||
'/api/v1/settings/notifications/webhook/test',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
types: values.types,
|
||||
options: {
|
||||
webhookUrl: values.webhookUrl,
|
||||
jsonPayload: JSON.stringify(values.jsonPayload),
|
||||
authHeader: values.authHeader,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import type { RadarrSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -166,19 +165,24 @@ const RadarrModal = ({ onClose, radarr, onSave }: RadarrModalProps) => {
|
||||
}) => {
|
||||
setIsTesting(true);
|
||||
try {
|
||||
const response = await axios.post<TestResponse>(
|
||||
'/api/v1/settings/radarr/test',
|
||||
{
|
||||
const res = await fetch('/api/v1/settings/radarr/test', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
hostname,
|
||||
apiKey,
|
||||
port: Number(port),
|
||||
baseUrl,
|
||||
useSsl,
|
||||
}
|
||||
);
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
setIsValidated(true);
|
||||
setTestResponse(response.data);
|
||||
setTestResponse(data);
|
||||
if (initialLoad.current) {
|
||||
addToast(intl.formatMessage(messages.toastRadarrTestSuccess), {
|
||||
appearance: 'success',
|
||||
@@ -271,12 +275,23 @@ const RadarrModal = ({ onClose, radarr, onSave }: RadarrModalProps) => {
|
||||
tagRequests: values.tagRequests,
|
||||
};
|
||||
if (!radarr) {
|
||||
await axios.post('/api/v1/settings/radarr', submission);
|
||||
const res = await fetch('/api/v1/settings/radarr', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
} else {
|
||||
await axios.put(
|
||||
`/api/v1/settings/radarr/${radarr.id}`,
|
||||
submission
|
||||
);
|
||||
const res = await fetch(`/api/v1/settings/radarr/${radarr.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
|
||||
onSave();
|
||||
|
||||
@@ -7,7 +7,6 @@ import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import { ApiErrorCode } from '@server/constants/error';
|
||||
import type { JellyfinSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import getConfig from 'next/config';
|
||||
import { useState } from 'react';
|
||||
@@ -167,9 +166,14 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
}
|
||||
|
||||
try {
|
||||
await axios.get('/api/v1/settings/jellyfin/library', {
|
||||
params,
|
||||
const searchParams = new URLSearchParams({
|
||||
sync: params.sync ? 'true' : 'false',
|
||||
...(params.enable ? { enable: params.enable } : {}),
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/jellyfin/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
setIsSyncing(false);
|
||||
revalidate();
|
||||
} catch (e) {
|
||||
@@ -206,16 +210,32 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
};
|
||||
|
||||
const startScan = async () => {
|
||||
await axios.post('/api/v1/settings/jellyfin/sync', {
|
||||
start: true,
|
||||
const res = await fetch('/api/v1/settings/jellyfin/sync', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
start: true,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
revalidateSync();
|
||||
};
|
||||
|
||||
const cancelScan = async () => {
|
||||
await axios.post('/api/v1/settings/jellyfin/sync', {
|
||||
cancel: true,
|
||||
const res = await fetch('/api/v1/settings/jellyfin/sync', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
cancel: true,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
revalidateSync();
|
||||
};
|
||||
|
||||
@@ -230,15 +250,19 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
.join(',');
|
||||
}
|
||||
|
||||
await axios.get('/api/v1/settings/jellyfin/library', {
|
||||
params,
|
||||
});
|
||||
const searchParams = new URLSearchParams(params.enable ? params : {});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/jellyfin/library?${searchParams.toString}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
} else {
|
||||
await axios.get('/api/v1/settings/jellyfin/library', {
|
||||
params: {
|
||||
enable: [...activeLibraries, libraryId].join(','),
|
||||
},
|
||||
const searchParams = new URLSearchParams({
|
||||
enable: [...activeLibraries, libraryId].join(','),
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/jellyfin/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
if (onComplete) {
|
||||
onComplete();
|
||||
@@ -447,14 +471,21 @@ const SettingsJellyfin: React.FC<SettingsJellyfinProps> = ({
|
||||
validationSchema={JellyfinSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/jellyfin', {
|
||||
ip: values.hostname,
|
||||
port: Number(values.port),
|
||||
useSsl: values.useSsl,
|
||||
urlBase: values.urlBase,
|
||||
externalHostname: values.jellyfinExternalUrl,
|
||||
jellyfinForgotPasswordUrl: values.jellyfinForgotPasswordUrl,
|
||||
} as JellyfinSettings);
|
||||
const res = await fetch('/api/v1/settings/jellyfin', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ip: values.hostname,
|
||||
port: Number(values.port),
|
||||
useSsl: values.useSsl,
|
||||
urlBase: values.urlBase,
|
||||
externalHostname: values.jellyfinExternalUrl,
|
||||
jellyfinForgotPasswordUrl: values.jellyfinForgotPasswordUrl,
|
||||
} as JellyfinSettings),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(
|
||||
intl.formatMessage(messages.jellyfinSettingsSuccess, {
|
||||
|
||||
@@ -19,7 +19,6 @@ import type {
|
||||
CacheResponse,
|
||||
} from '@server/interfaces/api/settingsInterfaces';
|
||||
import type { JobId } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import cronstrue from 'cronstrue/i18n';
|
||||
import { Fragment, useReducer, useState } from 'react';
|
||||
import type { MessageDescriptor } from 'react-intl';
|
||||
@@ -173,7 +172,10 @@ const SettingsJobs = () => {
|
||||
}
|
||||
|
||||
const runJob = async (job: Job) => {
|
||||
await axios.post(`/api/v1/settings/jobs/${job.id}/run`);
|
||||
const res = await fetch(`/api/v1/settings/jobs/${job.id}/run`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(
|
||||
intl.formatMessage(messages.jobstarted, {
|
||||
jobname: intl.formatMessage(messages[job.id] ?? messages.unknownJob),
|
||||
@@ -187,7 +189,10 @@ const SettingsJobs = () => {
|
||||
};
|
||||
|
||||
const cancelJob = async (job: Job) => {
|
||||
await axios.post(`/api/v1/settings/jobs/${job.id}/cancel`);
|
||||
const res = await fetch(`/api/v1/settings/jobs/${job.id}/cancel`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(
|
||||
intl.formatMessage(messages.jobcancelled, {
|
||||
jobname: intl.formatMessage(messages[job.id] ?? messages.unknownJob),
|
||||
@@ -201,7 +206,10 @@ const SettingsJobs = () => {
|
||||
};
|
||||
|
||||
const flushCache = async (cache: CacheItem) => {
|
||||
await axios.post(`/api/v1/settings/cache/${cache.id}/flush`);
|
||||
const res = await fetch(`/api/v1/settings/cache/${cache.id}/flush`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(
|
||||
intl.formatMessage(messages.cacheflushed, { cachename: cache.name }),
|
||||
{
|
||||
@@ -228,12 +236,19 @@ const SettingsJobs = () => {
|
||||
}
|
||||
|
||||
setIsSaving(true);
|
||||
await axios.post(
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/jobs/${jobModalState.job.id}/schedule`,
|
||||
{
|
||||
schedule: jobScheduleCron.join(' '),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
schedule: jobScheduleCron.join(' '),
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.jobScheduleEditSaved), {
|
||||
appearance: 'success',
|
||||
|
||||
@@ -17,7 +17,6 @@ import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import { ArrowPathIcon } from '@heroicons/react/24/solid';
|
||||
import type { UserSettingsGeneralResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import type { MainSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -87,7 +86,10 @@ const SettingsMain = () => {
|
||||
|
||||
const regenerate = async () => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/main/regenerate');
|
||||
const res = await fetch('/api/v1/settings/main/regenerate', {
|
||||
method: 'POST',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
revalidate();
|
||||
addToast(intl.formatMessage(messages.toastApiKeySuccess), {
|
||||
@@ -140,18 +142,25 @@ const SettingsMain = () => {
|
||||
validationSchema={MainSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/main', {
|
||||
applicationTitle: values.applicationTitle,
|
||||
applicationUrl: values.applicationUrl,
|
||||
csrfProtection: values.csrfProtection,
|
||||
hideAvailable: values.hideAvailable,
|
||||
locale: values.locale,
|
||||
region: values.region,
|
||||
originalLanguage: values.originalLanguage,
|
||||
partialRequestsEnabled: values.partialRequestsEnabled,
|
||||
trustProxy: values.trustProxy,
|
||||
cacheImages: values.cacheImages,
|
||||
const res = await fetch('/api/v1/settings/main', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
applicationTitle: values.applicationTitle,
|
||||
applicationUrl: values.applicationUrl,
|
||||
csrfProtection: values.csrfProtection,
|
||||
hideAvailable: values.hideAvailable,
|
||||
locale: values.locale,
|
||||
region: values.region,
|
||||
originalLanguage: values.originalLanguage,
|
||||
partialRequestsEnabled: values.partialRequestsEnabled,
|
||||
trustProxy: values.trustProxy,
|
||||
cacheImages: values.cacheImages,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
mutate('/api/v1/status');
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
} from '@heroicons/react/24/solid';
|
||||
import type { PlexDevice } from '@server/interfaces/api/plexInterfaces';
|
||||
import type { PlexSettings, TautulliSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { orderBy } from 'lodash';
|
||||
import { useMemo, useState } from 'react';
|
||||
@@ -241,9 +240,15 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
params.enable = activeLibraries.join(',');
|
||||
}
|
||||
|
||||
await axios.get('/api/v1/settings/plex/library', {
|
||||
params,
|
||||
const searchParams = new URLSearchParams({
|
||||
sync: params.sync ? 'true' : 'false',
|
||||
...(params.enable ? { enable: params.enable } : {}),
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/plex/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
setIsSyncing(false);
|
||||
revalidate();
|
||||
};
|
||||
@@ -262,11 +267,12 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
const response = await axios.get<PlexDevice[]>(
|
||||
'/api/v1/settings/plex/devices/servers'
|
||||
);
|
||||
if (response.data) {
|
||||
setAvailableServers(response.data);
|
||||
const res = await fetch('/api/v1/settings/plex/devices/servers');
|
||||
if (!res.ok) throw new Error();
|
||||
const data: PlexDevice[] = await res.json();
|
||||
|
||||
if (data) {
|
||||
setAvailableServers(data);
|
||||
}
|
||||
if (toastId) {
|
||||
removeToast(toastId);
|
||||
@@ -289,16 +295,30 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
};
|
||||
|
||||
const startScan = async () => {
|
||||
await axios.post('/api/v1/settings/plex/sync', {
|
||||
start: true,
|
||||
const res = await fetch('/api/v1/settings/plex/sync', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
start: true,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
revalidateSync();
|
||||
};
|
||||
|
||||
const cancelScan = async () => {
|
||||
await axios.post('/api/v1/settings/plex/sync', {
|
||||
cancel: true,
|
||||
const res = await fetch('/api/v1/settings/plex/sync', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
cancel: true,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
revalidateSync();
|
||||
};
|
||||
|
||||
@@ -313,15 +333,19 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
.join(',');
|
||||
}
|
||||
|
||||
await axios.get('/api/v1/settings/plex/library', {
|
||||
params,
|
||||
});
|
||||
const searchParams = new URLSearchParams(params.enable ? params : {});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/plex/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
} else {
|
||||
await axios.get('/api/v1/settings/plex/library', {
|
||||
params: {
|
||||
enable: [...activeLibraries, libraryId].join(','),
|
||||
},
|
||||
const searchParams = new URLSearchParams({
|
||||
enable: [...activeLibraries, libraryId].join(','),
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/plex/library?${searchParams.toString()}`
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
setIsSyncing(false);
|
||||
revalidate();
|
||||
@@ -385,12 +409,19 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
toastId = id;
|
||||
}
|
||||
);
|
||||
await axios.post('/api/v1/settings/plex', {
|
||||
ip: values.hostname,
|
||||
port: Number(values.port),
|
||||
useSsl: values.useSsl,
|
||||
webAppUrl: values.webAppUrl,
|
||||
} as PlexSettings);
|
||||
const res = await fetch('/api/v1/settings/plex', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ip: values.hostname,
|
||||
port: Number(values.port),
|
||||
useSsl: values.useSsl,
|
||||
webAppUrl: values.webAppUrl,
|
||||
} as PlexSettings),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
syncLibraries();
|
||||
|
||||
@@ -748,14 +779,27 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
||||
validationSchema={TautulliSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/tautulli', {
|
||||
hostname: values.tautulliHostname,
|
||||
port: Number(values.tautulliPort),
|
||||
useSsl: values.tautulliUseSsl,
|
||||
urlBase: values.tautulliUrlBase,
|
||||
apiKey: values.tautulliApiKey,
|
||||
externalUrl: values.tautulliExternalUrl,
|
||||
} as TautulliSettings);
|
||||
const res = await fetch('/api/v1/settings/tautulli', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
hostname: values.tautulliHostname,
|
||||
port: Number(values.tautulliPort),
|
||||
useSsl: values.tautulliUseSsl,
|
||||
urlBase: values.tautulliUrlBase,
|
||||
apiKey: values.tautulliApiKey,
|
||||
externalUrl: values.tautulliExternalUrl,
|
||||
} as TautulliSettings),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error('Failed to fetch');
|
||||
}
|
||||
|
||||
// Continue with any necessary processing
|
||||
|
||||
addToast(
|
||||
intl.formatMessage(messages.toastTautulliSettingsSuccess),
|
||||
|
||||
@@ -13,7 +13,6 @@ import defineMessages from '@app/utils/defineMessages';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/solid';
|
||||
import type { RadarrSettings, SonarrSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Fragment, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import useSWR, { mutate } from 'swr';
|
||||
@@ -196,9 +195,14 @@ const SettingsServices = () => {
|
||||
});
|
||||
|
||||
const deleteServer = async () => {
|
||||
await axios.delete(
|
||||
`/api/v1/settings/${deleteServerModal.type}/${deleteServerModal.serverId}`
|
||||
const res = await fetch(
|
||||
`/api/v1/settings/${deleteServerModal.type}/${deleteServerModal.serverId}`,
|
||||
{
|
||||
method: 'DELETE',
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
setDeleteServerModal({ open: false, serverId: null, type: 'radarr' });
|
||||
revalidateRadarr();
|
||||
revalidateSonarr();
|
||||
|
||||
@@ -9,7 +9,6 @@ import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import { MediaServerType } from '@server/constants/server';
|
||||
import type { MainSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import getConfig from 'next/config';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -77,21 +76,28 @@ const SettingsUsers = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/settings/main', {
|
||||
localLogin: values.localLogin,
|
||||
newPlexLogin: values.newPlexLogin,
|
||||
defaultQuotas: {
|
||||
movie: {
|
||||
quotaLimit: values.movieQuotaLimit,
|
||||
quotaDays: values.movieQuotaDays,
|
||||
},
|
||||
tv: {
|
||||
quotaLimit: values.tvQuotaLimit,
|
||||
quotaDays: values.tvQuotaDays,
|
||||
},
|
||||
const res = await fetch('/api/v1/settings/main', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
defaultPermissions: values.defaultPermissions,
|
||||
body: JSON.stringify({
|
||||
localLogin: values.localLogin,
|
||||
newPlexLogin: values.newPlexLogin,
|
||||
defaultQuotas: {
|
||||
movie: {
|
||||
quotaLimit: values.movieQuotaLimit,
|
||||
quotaDays: values.movieQuotaDays,
|
||||
},
|
||||
tv: {
|
||||
quotaLimit: values.tvQuotaLimit,
|
||||
quotaDays: values.tvQuotaDays,
|
||||
},
|
||||
},
|
||||
defaultPermissions: values.defaultPermissions,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
|
||||
addToast(intl.formatMessage(messages.toastSettingsSuccess), {
|
||||
|
||||
@@ -4,7 +4,6 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import type { SonarrSettings } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { Field, Formik } from 'formik';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -177,19 +176,24 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
|
||||
}) => {
|
||||
setIsTesting(true);
|
||||
try {
|
||||
const response = await axios.post<TestResponse>(
|
||||
'/api/v1/settings/sonarr/test',
|
||||
{
|
||||
const res = await fetch('/api/v1/settings/sonarr/test', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
hostname,
|
||||
apiKey,
|
||||
port: Number(port),
|
||||
baseUrl,
|
||||
useSsl,
|
||||
}
|
||||
);
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data: TestResponse = await res.json();
|
||||
|
||||
setIsValidated(true);
|
||||
setTestResponse(response.data);
|
||||
setTestResponse(data);
|
||||
if (initialLoad.current) {
|
||||
addToast(intl.formatMessage(messages.toastSonarrTestSuccess), {
|
||||
appearance: 'success',
|
||||
@@ -306,12 +310,23 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
|
||||
tagRequests: values.tagRequests,
|
||||
};
|
||||
if (!sonarr) {
|
||||
await axios.post('/api/v1/settings/sonarr', submission);
|
||||
const res = await fetch('/api/v1/settings/sonarr', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
} else {
|
||||
await axios.put(
|
||||
`/api/v1/settings/sonarr/${sonarr.id}`,
|
||||
submission
|
||||
);
|
||||
const res = await fetch(`/api/v1/settings/sonarr/${sonarr.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(submission),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
}
|
||||
|
||||
onSave();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import PlexLoginButton from '@app/components/PlexLoginButton';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import axios from 'axios';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
@@ -25,9 +24,19 @@ const LoginWithPlex = ({ onComplete }: LoginWithPlexProps) => {
|
||||
|
||||
useEffect(() => {
|
||||
const login = async () => {
|
||||
const response = await axios.post('/api/v1/auth/plex', { authToken });
|
||||
const res = await fetch('/api/v1/auth/plex', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
authToken,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
if (response.data?.id) {
|
||||
if (data?.id) {
|
||||
revalidate();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@ import PlexLoginButton from '@app/components/PlexLoginButton';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { MediaServerType } from '@server/constants/server';
|
||||
import axios from 'axios';
|
||||
import getConfig from 'next/config';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
@@ -34,11 +33,19 @@ const SetupLogin: React.FC<LoginWithMediaServerProps> = ({ onComplete }) => {
|
||||
|
||||
useEffect(() => {
|
||||
const login = async () => {
|
||||
const response = await axios.post('/api/v1/auth/plex', {
|
||||
authToken: authToken,
|
||||
const res = await fetch('/api/v1/auth/plex', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
authToken: authToken,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data = await res.json();
|
||||
|
||||
if (response.data?.email) {
|
||||
if (data?.email) {
|
||||
revalidate();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,7 +11,6 @@ import SetupSteps from '@app/components/Setup/SetupSteps';
|
||||
import useLocale from '@app/hooks/useLocale';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { MediaServerType } from '@server/constants/server';
|
||||
import axios from 'axios';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
@@ -46,15 +45,27 @@ const Setup = () => {
|
||||
|
||||
const finishSetup = async () => {
|
||||
setIsUpdating(true);
|
||||
const response = await axios.post<{ initialized: boolean }>(
|
||||
'/api/v1/settings/initialize'
|
||||
);
|
||||
const res = await fetch('/api/v1/settings/initialize', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data: { initialized: boolean } = await res.json();
|
||||
|
||||
setIsUpdating(false);
|
||||
if (response.data.initialized) {
|
||||
await axios.post('/api/v1/settings/main', { locale });
|
||||
mutate('/api/v1/settings/public');
|
||||
if (data.initialized) {
|
||||
const mainRes = await fetch('/api/v1/settings/main', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ locale }),
|
||||
});
|
||||
if (!mainRes.ok) throw new Error();
|
||||
|
||||
mutate('/api/v1/settings/public');
|
||||
router.push('/');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@ import Button from '@app/components/Common/Button';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { CheckIcon, TrashIcon } from '@heroicons/react/24/solid';
|
||||
import axios from 'axios';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { mutate } from 'swr';
|
||||
|
||||
@@ -21,11 +20,14 @@ const messages = defineMessages('components.TitleCard', {
|
||||
cleardata: 'Clear Data',
|
||||
});
|
||||
|
||||
const Error = ({ id, tmdbId, tvdbId, type, canExpand }: ErrorCardProps) => {
|
||||
const ErrorCard = ({ id, tmdbId, tvdbId, type, canExpand }: ErrorCardProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const deleteMedia = async () => {
|
||||
await axios.delete(`/api/v1/media/${id}`);
|
||||
const res = await fetch(`/api/v1/media/${id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/media?filter=allavailable&take=20&sort=mediaAdded');
|
||||
mutate('/api/v1/request?filter=all&take=10&sort=modified&skip=0');
|
||||
};
|
||||
@@ -129,4 +131,4 @@ const Error = ({ id, tmdbId, tvdbId, type, canExpand }: ErrorCardProps) => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Error;
|
||||
export default ErrorCard;
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
import { MediaStatus } from '@server/constants/media';
|
||||
import type { Watchlist } from '@server/entity/Watchlist';
|
||||
import type { MediaType } from '@server/models/Search';
|
||||
import axios from 'axios';
|
||||
import Link from 'next/link';
|
||||
import { Fragment, useCallback, useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -98,13 +97,21 @@ const TitleCard = ({
|
||||
const onClickWatchlistBtn = async (): Promise<void> => {
|
||||
setIsUpdating(true);
|
||||
try {
|
||||
const response = await axios.post<Watchlist>('/api/v1/watchlist', {
|
||||
tmdbId: id,
|
||||
mediaType,
|
||||
title,
|
||||
const res = await fetch('/api/v1/watchlist', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
tmdbId: id,
|
||||
mediaType,
|
||||
title,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const data: Watchlist = await res.json();
|
||||
mutate('/api/v1/discover/watchlist');
|
||||
if (response.data) {
|
||||
if (data) {
|
||||
addToast(
|
||||
<span>
|
||||
{intl.formatMessage(messages.watchlistSuccess, {
|
||||
@@ -129,9 +136,11 @@ const TitleCard = ({
|
||||
const onClickDeleteWatchlistBtn = async (): Promise<void> => {
|
||||
setIsUpdating(true);
|
||||
try {
|
||||
const response = await axios.delete<Watchlist>('/api/v1/watchlist/' + id);
|
||||
|
||||
if (response.status === 204) {
|
||||
const res = await fetch('/api/v1/watchlist/' + id, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
if (res.status === 204) {
|
||||
addToast(
|
||||
<span>
|
||||
{intl.formatMessage(messages.watchlistDeleted, {
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { User } from '@app/hooks/useUser';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import axios from 'axios';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -45,10 +44,18 @@ const BulkEditModal = ({
|
||||
const updateUsers = async () => {
|
||||
try {
|
||||
setIsSaving(true);
|
||||
const { data: updated } = await axios.put<User[]>(`/api/v1/user`, {
|
||||
ids: selectedUserIds,
|
||||
permissions: currentPermission,
|
||||
const res = await fetch('/api/v1/user', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
ids: selectedUserIds,
|
||||
permissions: currentPermission,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const updated: User[] = await res.json();
|
||||
if (onComplete) {
|
||||
onComplete(updated);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import useSettings from '@app/hooks/useSettings';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import type { UserResultsResponse } from '@server/interfaces/api/userInterfaces';
|
||||
import axios from 'axios';
|
||||
import getConfig from 'next/config';
|
||||
import Image from 'next/image';
|
||||
import { useState } from 'react';
|
||||
@@ -69,10 +68,17 @@ const JellyfinImportModal: React.FC<JellyfinImportProps> = ({
|
||||
setImporting(true);
|
||||
|
||||
try {
|
||||
const { data: createdUsers } = await axios.post(
|
||||
'/api/v1/user/import-from-jellyfin',
|
||||
{ jellyfinUserIds: selectedUsers }
|
||||
);
|
||||
const res = await fetch('/api/v1/user/import-from-jellyfin', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
jellyfinUserIds: selectedUsers,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const { data: createdUsers } = await res.json();
|
||||
|
||||
if (!createdUsers.length) {
|
||||
throw new Error('No users were imported from Jellyfin.');
|
||||
|
||||
@@ -3,7 +3,6 @@ import Modal from '@app/components/Common/Modal';
|
||||
import useSettings from '@app/hooks/useSettings';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import axios from 'axios';
|
||||
import Image from 'next/image';
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -48,10 +47,17 @@ const PlexImportModal = ({ onCancel, onComplete }: PlexImportProps) => {
|
||||
setImporting(true);
|
||||
|
||||
try {
|
||||
const { data: createdUsers } = await axios.post(
|
||||
'/api/v1/user/import-from-plex',
|
||||
{ plexIds: selectedUsers }
|
||||
);
|
||||
const res = await fetch('/api/v1/user/import-from-plex', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
plexIds: selectedUsers,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const { data: createdUsers } = await res.json();
|
||||
|
||||
if (!createdUsers.length) {
|
||||
throw new Error('No users were imported from Plex.');
|
||||
|
||||
@@ -27,7 +27,6 @@ import {
|
||||
import { MediaServerType } from '@server/constants/server';
|
||||
import type { UserResultsResponse } from '@server/interfaces/api/userInterfaces';
|
||||
import { hasPermission } from '@server/lib/permissions';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import getConfig from 'next/config';
|
||||
import Image from 'next/image';
|
||||
@@ -183,7 +182,10 @@ const UserList = () => {
|
||||
setDeleting(true);
|
||||
|
||||
try {
|
||||
await axios.delete(`/api/v1/user/${deleteModal.user?.id}`);
|
||||
const res = await fetch(`/api/v1/user/${deleteModal.user?.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.userdeleted), {
|
||||
autoDismiss: true,
|
||||
@@ -282,11 +284,18 @@ const UserList = () => {
|
||||
validationSchema={CreateUserSchema}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post('/api/v1/user', {
|
||||
username: values.displayName,
|
||||
email: values.email,
|
||||
password: values.genpassword ? null : values.password,
|
||||
const res = await fetch('/api/v1/user', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: values.displayName,
|
||||
email: values.email,
|
||||
password: values.genpassword ? null : values.password,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.usercreatedsuccess), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -11,11 +11,10 @@ import useLocale from '@app/hooks/useLocale';
|
||||
import useSettings from '@app/hooks/useSettings';
|
||||
import { Permission, UserType, useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import Error from '@app/pages/_error';
|
||||
import ErrorPage from '@app/pages/_error';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import type { UserSettingsGeneralResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import getConfig from 'next/config';
|
||||
import { useRouter } from 'next/router';
|
||||
@@ -116,7 +115,7 @@ const UserGeneralSettings = () => {
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return <Error statusCode={500} />;
|
||||
return <ErrorPage statusCode={500} />;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -151,22 +150,31 @@ const UserGeneralSettings = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/main`, {
|
||||
username: values.displayName,
|
||||
email: values.email,
|
||||
discordId: values.discordId,
|
||||
locale: values.locale,
|
||||
region: values.region,
|
||||
originalLanguage: values.originalLanguage,
|
||||
movieQuotaLimit: movieQuotaEnabled
|
||||
? values.movieQuotaLimit
|
||||
: null,
|
||||
movieQuotaDays: movieQuotaEnabled ? values.movieQuotaDays : null,
|
||||
tvQuotaLimit: tvQuotaEnabled ? values.tvQuotaLimit : null,
|
||||
tvQuotaDays: tvQuotaEnabled ? values.tvQuotaDays : null,
|
||||
watchlistSyncMovies: values.watchlistSyncMovies,
|
||||
watchlistSyncTv: values.watchlistSyncTv,
|
||||
const res = await fetch(`/api/v1/user/${user?.id}/settings/main`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: values.displayName,
|
||||
email: values.email,
|
||||
discordId: values.discordId,
|
||||
locale: values.locale,
|
||||
region: values.region,
|
||||
originalLanguage: values.originalLanguage,
|
||||
movieQuotaLimit: movieQuotaEnabled
|
||||
? values.movieQuotaLimit
|
||||
: null,
|
||||
movieQuotaDays: movieQuotaEnabled
|
||||
? values.movieQuotaDays
|
||||
: null,
|
||||
tvQuotaLimit: tvQuotaEnabled ? values.tvQuotaLimit : null,
|
||||
tvQuotaDays: tvQuotaEnabled ? values.tvQuotaDays : null,
|
||||
watchlistSyncMovies: values.watchlistSyncMovies,
|
||||
watchlistSyncTv: values.watchlistSyncTv,
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
if (currentUser?.id === user?.id && setLocale) {
|
||||
setLocale(
|
||||
|
||||
@@ -6,7 +6,6 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -68,18 +67,28 @@ const UserNotificationsDiscord = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: values.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
discord: values.types,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/user/${user?.id}/settings/notifications`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: values.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
discord: values.types,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.discordsettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -11,7 +11,6 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import axios from 'axios';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -67,18 +66,28 @@ const UserEmailSettings = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {
|
||||
pgpKey: values.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
email: values.types,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/user/${user?.id}/settings/notifications`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
pgpKey: values.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
email: values.types,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.emailsettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -6,7 +6,6 @@ import { useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import axios from 'axios';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -65,18 +64,28 @@ const UserPushbulletSettings = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: values.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
pushbullet: values.types,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/user/${user?.id}/settings/notifications`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: values.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
pushbullet: values.types,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.pushbulletsettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -7,7 +7,6 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import type { PushoverSound } from '@server/api/pushover';
|
||||
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -97,18 +96,28 @@ const UserPushoverSettings = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: values.pushoverApplicationToken,
|
||||
pushoverUserKey: values.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
pushover: values.types,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/user/${user?.id}/settings/notifications`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: values.pushoverApplicationToken,
|
||||
pushoverUserKey: values.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
pushover: values.types,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.pushoversettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -6,7 +6,6 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import axios from 'axios';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -71,18 +70,28 @@ const UserTelegramSettings = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: values.telegramChatId,
|
||||
telegramSendSilently: values.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
telegram: values.types,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/user/${user?.id}/settings/notifications`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: values.telegramChatId,
|
||||
telegramSendSilently: values.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
telegram: values.types,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.telegramsettingssaved), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -8,7 +8,6 @@ import globalMessages from '@app/i18n/globalMessages';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||
import axios from 'axios';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -48,18 +47,28 @@ const UserWebPushSettings = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, {
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
webpush: values.types,
|
||||
},
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/user/${user?.id}/settings/notifications`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
pgpKey: data?.pgpKey,
|
||||
discordId: data?.discordId,
|
||||
pushbulletAccessToken: data?.pushbulletAccessToken,
|
||||
pushoverApplicationToken: data?.pushoverApplicationToken,
|
||||
pushoverUserKey: data?.pushoverUserKey,
|
||||
telegramChatId: data?.telegramChatId,
|
||||
telegramSendSilently: data?.telegramSendSilently,
|
||||
notificationTypes: {
|
||||
webpush: values.types,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
mutate('/api/v1/settings/public');
|
||||
addToast(intl.formatMessage(messages.webpushsettingssaved), {
|
||||
appearance: 'success',
|
||||
|
||||
@@ -5,10 +5,9 @@ import PageTitle from '@app/components/Common/PageTitle';
|
||||
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
||||
import { Permission, useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import Error from '@app/pages/_error';
|
||||
import ErrorPage from '@app/pages/_error';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -80,7 +79,7 @@ const UserPasswordChange = () => {
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return <Error statusCode={500} />;
|
||||
return <ErrorPage statusCode={500} />;
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -123,11 +122,21 @@ const UserPasswordChange = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values, { resetForm }) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/password`, {
|
||||
currentPassword: values.currentPassword,
|
||||
newPassword: values.newPassword,
|
||||
confirmPassword: values.confirmPassword,
|
||||
});
|
||||
const res = await fetch(
|
||||
`/api/v1/user/${user?.id}/settings/password`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
currentPassword: values.currentPassword,
|
||||
newPassword: values.newPassword,
|
||||
confirmPassword: values.confirmPassword,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
|
||||
addToast(intl.formatMessage(messages.toastSettingsSuccess), {
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -5,10 +5,9 @@ import PageTitle from '@app/components/Common/PageTitle';
|
||||
import PermissionEdit from '@app/components/PermissionEdit';
|
||||
import { useUser } from '@app/hooks/useUser';
|
||||
import globalMessages from '@app/i18n/globalMessages';
|
||||
import Error from '@app/pages/_error';
|
||||
import ErrorPage from '@app/pages/_error';
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline';
|
||||
import axios from 'axios';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -46,7 +45,7 @@ const UserPermissions = () => {
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return <Error statusCode={500} />;
|
||||
return <ErrorPage statusCode={500} />;
|
||||
}
|
||||
|
||||
if (currentUser?.id !== 1 && currentUser?.id === user?.id) {
|
||||
@@ -84,10 +83,19 @@ const UserPermissions = () => {
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await axios.post(`/api/v1/user/${user?.id}/settings/permissions`, {
|
||||
permissions: values.currentPermissions ?? 0,
|
||||
});
|
||||
|
||||
const res = await fetch(
|
||||
`/api/v1/user/${user?.id}/settings/permissions`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
permissions: values.currentPermissions ?? 0,
|
||||
}),
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error();
|
||||
addToast(intl.formatMessage(messages.toastSettingsSuccess), {
|
||||
autoDismiss: true,
|
||||
appearance: 'success',
|
||||
|
||||
Reference in New Issue
Block a user