fix: adding new checks for plex connection/disconnection in user settings

pull/3105/head
sct 2 years ago
parent ca01d4dd6f
commit 6f5f615ffe

@ -199,6 +199,10 @@ authRoutes.get('/plex/unlink', isAuthenticated(), async (req, res, next) => {
const user = await userRepository.findOneByOrFail({ id: req.user.id }); 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.plexId = null;
user.plexToken = null; user.plexToken = null;
user.avatar = gravatarUrl(user.email, { default: 'mm', size: 200 }); user.avatar = gravatarUrl(user.email, { default: 'mm', size: 200 });

@ -8,6 +8,10 @@ type TooltipProps = {
children: React.ReactElement; children: React.ReactElement;
tooltipConfig?: Partial<Config>; tooltipConfig?: Partial<Config>;
className?: string; className?: string;
/**
* When true, the tooltip will not be shown
*/
disabled?: boolean;
}; };
const Tooltip = ({ const Tooltip = ({
@ -15,6 +19,7 @@ const Tooltip = ({
content, content,
tooltipConfig, tooltipConfig,
className, className,
disabled,
}: TooltipProps) => { }: TooltipProps) => {
const { getTooltipProps, setTooltipRef, setTriggerRef, visible } = const { getTooltipProps, setTooltipRef, setTriggerRef, visible } =
usePopperTooltip({ usePopperTooltip({
@ -24,6 +29,10 @@ const Tooltip = ({
...tooltipConfig, ...tooltipConfig,
}); });
if (disabled) {
return children;
}
const tooltipStyle = [ 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', '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; onError?: (message: string) => void;
textOverride?: string; textOverride?: string;
svgIcon?: React.ReactNode; svgIcon?: React.ReactNode;
disabled?: boolean;
}; };
const PlexLoginButton = ({ const PlexLoginButton = ({
@ -31,6 +32,7 @@ const PlexLoginButton = ({
buttonType = 'plex', buttonType = 'plex',
buttonSize, buttonSize,
svgIcon, svgIcon,
disabled,
}: PlexLoginButtonProps) => { }: PlexLoginButtonProps) => {
const intl = useIntl(); const intl = useIntl();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -56,7 +58,7 @@ const PlexLoginButton = ({
plexOAuth.preparePopup(); plexOAuth.preparePopup();
setTimeout(() => getPlexLogin(), 1500); setTimeout(() => getPlexLogin(), 1500);
}} }}
disabled={loading || isProcessing} disabled={loading || isProcessing || disabled}
buttonType={buttonType} buttonType={buttonType}
buttonSize={buttonSize} buttonSize={buttonSize}
> >

@ -2,6 +2,7 @@ import PlexLogo from '@app/assets/services/plex.svg';
import Button from '@app/components/Common/Button'; import Button from '@app/components/Common/Button';
import LoadingSpinner from '@app/components/Common/LoadingSpinner'; import LoadingSpinner from '@app/components/Common/LoadingSpinner';
import PageTitle from '@app/components/Common/PageTitle'; import PageTitle from '@app/components/Common/PageTitle';
import Tooltip from '@app/components/Common/Tooltip';
import LanguageSelector from '@app/components/LanguageSelector'; import LanguageSelector from '@app/components/LanguageSelector';
import QuotaSelector from '@app/components/QuotaSelector'; import QuotaSelector from '@app/components/QuotaSelector';
import RegionSelector from '@app/components/RegionSelector'; import RegionSelector from '@app/components/RegionSelector';
@ -61,6 +62,16 @@ const messages = defineMessages({
plexwatchlistsyncseries: 'Auto-Request Series', plexwatchlistsyncseries: 'Auto-Request Series',
plexwatchlistsyncseriestip: plexwatchlistsyncseriestip:
'Automatically request series on your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>', '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 = () => { const UserGeneralSettings = () => {
@ -106,13 +117,13 @@ const UserGeneralSettings = () => {
try { try {
await axios.get('/api/v1/auth/plex/unlink'); await axios.get('/api/v1/auth/plex/unlink');
addToast('Plex account is no longer connected.', { addToast(intl.formatMessage(messages.plexdisconnectedsuccess), {
appearance: 'success', appearance: 'success',
autoDismiss: true, autoDismiss: true,
}); });
revalidateUser(); revalidateUser();
} catch (e) { } catch (e) {
addToast('Failed to disconnect Plex account.', { addToast(intl.formatMessage(messages.plexdisconnectedfailure), {
appearance: 'error', appearance: 'error',
autoDismiss: true, autoDismiss: true,
}); });
@ -211,55 +222,94 @@ const UserGeneralSettings = () => {
<label className="text-label"> <label className="text-label">
{intl.formatMessage(messages.connectedaccounts)} {intl.formatMessage(messages.connectedaccounts)}
</label> </label>
<div className="flex items-center rounded sm:col-span-2"> {!currentSettings.plexLoginEnabled && user?.id !== 1 && (
<div className="mr-4 flex h-7 w-7 items-center justify-center rounded-full border border-gray-700 bg-gray-800"> <div className="mb-1 text-sm font-medium leading-5 text-gray-400 sm:mt-2">
<CheckCircleIcon <div className="flex max-w-lg items-center">
className={`w-full ${ {intl.formatMessage(messages.noconnectedavailable)}
user?.isPlexUser ? 'text-green-500' : 'text-gray-700' </div>
}`}
/>
</div> </div>
<PlexLogo className="h-8 border-r border-gray-700 pr-4" /> )}
{!user?.isPlexUser ? ( {(currentSettings.plexLoginEnabled || user?.id === 1) && (
<> <div className="flex items-center rounded sm:col-span-2">
<div className="ml-4"> <div className="mr-4 flex h-7 w-7 items-center justify-center rounded-full border border-gray-700 bg-gray-800">
<LoginWithPlex <CheckCircleIcon
onComplete={() => { className={`h-full w-full ${
revalidateUser(); user?.isPlexUser ? 'text-green-500' : 'text-gray-700'
}} }`}
textOverride="Connect Plex Account" />
/> </div>
</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 className="ml-4">
<LoginWithPlex
onComplete={() => {
addToast('Refreshed Plex token.', {
appearance: 'success',
autoDismiss: true,
});
revalidateUser();
}}
svgIcon={<RefreshIcon />}
textOverride="Refresh Token"
buttonSize="sm"
buttonType="primary"
/>
</div> </div>
<Button ) : (
type="button" <>
className="ml-4" {!user?.isPlexUser ? (
buttonSize="sm" <>
onClick={() => unlinkPlex()} <div className="ml-4">
> <LoginWithPlex
<XCircleIcon /> onComplete={() => {
<span>Disconnect Plex</span> revalidateUser();
</Button> }}
</> textOverride={intl.formatMessage(
)} messages.connectplexaccount
</div> )}
/>
</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>
<div className="form-row"> <div className="form-row">
<label className="text-label"> <label className="text-label">

@ -198,7 +198,7 @@ CoreApp.getInitialProps = async (initialProps) => {
const initialized = response.data.initialized; const initialized = response.data.initialized;
if (!initialized) { if (!initialized) {
if (!router.pathname.match(/(setup|login\/plex)/)) { if (!router.pathname.match(/(setup|login\/plex|loading)/)) {
ctx.res.writeHead(307, { ctx.res.writeHead(307, {
Location: '/setup', Location: '/setup',
}); });

Loading…
Cancel
Save