mirror of
https://github.com/sct/overseerr.git
synced 2025-12-26 08:25:07 +01:00
fix: adding new checks for plex connection/disconnection in user settings
This commit is contained in:
@@ -198,6 +198,10 @@ authRoutes.get('/plex/unlink', isAuthenticated(), async (req, res, next) => {
|
||||
|
||||
const user = await userRepository.findOneByOrFail({ id: req.user.id });
|
||||
|
||||
if (!user.isLocalUser) {
|
||||
throw new Error('User must have a local password set to unlink Plex.');
|
||||
}
|
||||
|
||||
user.plexId = null;
|
||||
user.plexToken = null;
|
||||
user.avatar = gravatarUrl(user.email, { default: 'mm', size: 200 });
|
||||
|
||||
@@ -8,6 +8,10 @@ type TooltipProps = {
|
||||
children: React.ReactElement;
|
||||
tooltipConfig?: Partial<Config>;
|
||||
className?: string;
|
||||
/**
|
||||
* When true, the tooltip will not be shown
|
||||
*/
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const Tooltip = ({
|
||||
@@ -15,6 +19,7 @@ const Tooltip = ({
|
||||
content,
|
||||
tooltipConfig,
|
||||
className,
|
||||
disabled,
|
||||
}: TooltipProps) => {
|
||||
const { getTooltipProps, setTooltipRef, setTriggerRef, visible } =
|
||||
usePopperTooltip({
|
||||
@@ -24,6 +29,10 @@ const Tooltip = ({
|
||||
...tooltipConfig,
|
||||
});
|
||||
|
||||
if (disabled) {
|
||||
return children;
|
||||
}
|
||||
|
||||
const tooltipStyle = [
|
||||
'z-50 text-sm absolute font-normal bg-gray-800 px-2 py-1 rounded border border-gray-600 shadow text-gray-100',
|
||||
];
|
||||
|
||||
@@ -21,6 +21,7 @@ type PlexLoginButtonProps = Pick<
|
||||
onError?: (message: string) => void;
|
||||
textOverride?: string;
|
||||
svgIcon?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const PlexLoginButton = ({
|
||||
@@ -31,6 +32,7 @@ const PlexLoginButton = ({
|
||||
buttonType = 'plex',
|
||||
buttonSize,
|
||||
svgIcon,
|
||||
disabled,
|
||||
}: PlexLoginButtonProps) => {
|
||||
const intl = useIntl();
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -56,7 +58,7 @@ const PlexLoginButton = ({
|
||||
plexOAuth.preparePopup();
|
||||
setTimeout(() => getPlexLogin(), 1500);
|
||||
}}
|
||||
disabled={loading || isProcessing}
|
||||
disabled={loading || isProcessing || disabled}
|
||||
buttonType={buttonType}
|
||||
buttonSize={buttonSize}
|
||||
>
|
||||
|
||||
@@ -2,6 +2,7 @@ import PlexLogo from '@app/assets/services/plex.svg';
|
||||
import Button from '@app/components/Common/Button';
|
||||
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
||||
import PageTitle from '@app/components/Common/PageTitle';
|
||||
import Tooltip from '@app/components/Common/Tooltip';
|
||||
import LanguageSelector from '@app/components/LanguageSelector';
|
||||
import QuotaSelector from '@app/components/QuotaSelector';
|
||||
import RegionSelector from '@app/components/RegionSelector';
|
||||
@@ -61,6 +62,16 @@ const messages = defineMessages({
|
||||
plexwatchlistsyncseries: 'Auto-Request Series',
|
||||
plexwatchlistsyncseriestip:
|
||||
'Automatically request series on your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>',
|
||||
noconnectedavailable: 'No connected services available.',
|
||||
onlyloggedinuseredit:
|
||||
'Only the logged in user can edit their own connected accounts.',
|
||||
connectplexaccount: 'Connect Plex Account',
|
||||
refreshedtoken: 'Refreshed Plex Token.',
|
||||
refreshtoken: 'Refresh Token',
|
||||
mustsetpasswordplex: 'You must set a password before disconnecting Plex.',
|
||||
disconnectPlex: 'Disconnect Plex',
|
||||
plexdisconnectedsuccess: 'Plex account disconnected.',
|
||||
plexdisconnectedfailure: 'Failed to disconnect Plex account.',
|
||||
});
|
||||
|
||||
const UserGeneralSettings = () => {
|
||||
@@ -106,13 +117,13 @@ const UserGeneralSettings = () => {
|
||||
try {
|
||||
await axios.get('/api/v1/auth/plex/unlink');
|
||||
|
||||
addToast('Plex account is no longer connected.', {
|
||||
addToast(intl.formatMessage(messages.plexdisconnectedsuccess), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
});
|
||||
revalidateUser();
|
||||
} catch (e) {
|
||||
addToast('Failed to disconnect Plex account.', {
|
||||
addToast(intl.formatMessage(messages.plexdisconnectedfailure), {
|
||||
appearance: 'error',
|
||||
autoDismiss: true,
|
||||
});
|
||||
@@ -211,55 +222,94 @@ const UserGeneralSettings = () => {
|
||||
<label className="text-label">
|
||||
{intl.formatMessage(messages.connectedaccounts)}
|
||||
</label>
|
||||
<div className="flex items-center rounded sm:col-span-2">
|
||||
<div className="mr-4 flex h-7 w-7 items-center justify-center rounded-full border border-gray-700 bg-gray-800">
|
||||
<CheckCircleIcon
|
||||
className={`w-full ${
|
||||
user?.isPlexUser ? 'text-green-500' : 'text-gray-700'
|
||||
}`}
|
||||
/>
|
||||
{!currentSettings.plexLoginEnabled && user?.id !== 1 && (
|
||||
<div className="mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2">
|
||||
<div className="flex max-w-lg items-center">
|
||||
{intl.formatMessage(messages.noconnectedavailable)}
|
||||
</div>
|
||||
</div>
|
||||
<PlexLogo className="h-8 border-r border-gray-700 pr-4" />
|
||||
{!user?.isPlexUser ? (
|
||||
<>
|
||||
<div className="ml-4">
|
||||
<LoginWithPlex
|
||||
onComplete={() => {
|
||||
revalidateUser();
|
||||
}}
|
||||
textOverride="Connect Plex Account"
|
||||
/>
|
||||
)}
|
||||
{(currentSettings.plexLoginEnabled || user?.id === 1) && (
|
||||
<div className="flex items-center rounded sm:col-span-2">
|
||||
<div className="mr-4 flex h-7 w-7 items-center justify-center rounded-full border border-gray-700 bg-gray-800">
|
||||
<CheckCircleIcon
|
||||
className={`h-full w-full ${
|
||||
user?.isPlexUser ? 'text-green-500' : 'text-gray-700'
|
||||
}`}
|
||||
/>
|
||||
</div>
|
||||
<PlexLogo className="h-8 border-r border-gray-700 pr-4" />
|
||||
{user?.id !== currentUser?.id ? (
|
||||
<div className="ml-4 text-sm text-gray-400">
|
||||
{intl.formatMessage(messages.onlyloggedinuseredit)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="ml-4">
|
||||
<LoginWithPlex
|
||||
onComplete={() => {
|
||||
addToast('Refreshed Plex token.', {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
});
|
||||
revalidateUser();
|
||||
}}
|
||||
svgIcon={<RefreshIcon />}
|
||||
textOverride="Refresh Token"
|
||||
buttonSize="sm"
|
||||
buttonType="primary"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
className="ml-4"
|
||||
buttonSize="sm"
|
||||
onClick={() => unlinkPlex()}
|
||||
>
|
||||
<XCircleIcon />
|
||||
<span>Disconnect Plex</span>
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{!user?.isPlexUser ? (
|
||||
<>
|
||||
<div className="ml-4">
|
||||
<LoginWithPlex
|
||||
onComplete={() => {
|
||||
revalidateUser();
|
||||
}}
|
||||
textOverride={intl.formatMessage(
|
||||
messages.connectplexaccount
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="ml-4">
|
||||
<LoginWithPlex
|
||||
onComplete={() => {
|
||||
addToast(
|
||||
intl.formatMessage(messages.refreshedtoken),
|
||||
{
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
}
|
||||
);
|
||||
revalidateUser();
|
||||
}}
|
||||
svgIcon={<RefreshIcon />}
|
||||
textOverride={intl.formatMessage(
|
||||
messages.refreshtoken
|
||||
)}
|
||||
buttonSize="sm"
|
||||
buttonType="primary"
|
||||
/>
|
||||
</div>
|
||||
<Tooltip
|
||||
content={intl.formatMessage(
|
||||
messages.mustsetpasswordplex
|
||||
)}
|
||||
// We only want to show the tooltip if the user is not a local user
|
||||
disabled={user?.isLocalUser}
|
||||
>
|
||||
<span>
|
||||
<Button
|
||||
type="button"
|
||||
className="ml-4"
|
||||
buttonSize="sm"
|
||||
onClick={() => unlinkPlex()}
|
||||
disabled={!user?.isLocalUser}
|
||||
>
|
||||
<XCircleIcon />
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
messages.disconnectPlex
|
||||
)}
|
||||
</span>
|
||||
</Button>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label className="text-label">
|
||||
|
||||
@@ -244,7 +244,7 @@ CoreApp.getInitialProps = async (initialProps) => {
|
||||
const initialized = response.data.initialized;
|
||||
|
||||
if (!initialized) {
|
||||
if (!router.pathname.match(/(setup|login\/plex)/)) {
|
||||
if (!router.pathname.match(/(setup|login\/plex|loading)/)) {
|
||||
ctx.res.writeHead(307, {
|
||||
Location: '/setup',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user