mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat: force setup if app is not initialized
This commit is contained in:
@@ -1160,6 +1160,7 @@ paths:
|
||||
/settings/public:
|
||||
get:
|
||||
summary: Returns public settings
|
||||
security: []
|
||||
description: Returns settings that are not protected or sensitive. Mainly used to determine if the app has been configured for the first time.
|
||||
tags:
|
||||
- settings
|
||||
@@ -1170,6 +1171,19 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PublicSettings'
|
||||
/settings/initialize:
|
||||
get:
|
||||
summary: Set the application as initialized
|
||||
description: Sets the app as initalized and allows the user to navigate to pages other than the setup page
|
||||
tags:
|
||||
- settings
|
||||
responses:
|
||||
'200':
|
||||
description: Public Settings returned
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PublicSettings'
|
||||
/settings/jobs:
|
||||
get:
|
||||
summary: Returns list of scheduled jobs
|
||||
@@ -1887,6 +1901,12 @@ paths:
|
||||
type: string
|
||||
nullable: true
|
||||
enum: [all, available, partial, processing, pending]
|
||||
- in: query
|
||||
name: sort
|
||||
schema:
|
||||
type: string
|
||||
enum: [added, modified]
|
||||
default: added
|
||||
responses:
|
||||
'200':
|
||||
description: Returned media
|
||||
|
@@ -16,6 +16,11 @@ const router = Router();
|
||||
|
||||
router.use(checkUser);
|
||||
router.use('/user', isAuthenticated(Permission.MANAGE_USERS), user);
|
||||
router.get('/settings/public', (_req, res) => {
|
||||
const settings = getSettings();
|
||||
|
||||
return res.status(200).json(settings.public);
|
||||
});
|
||||
router.use(
|
||||
'/settings',
|
||||
isAuthenticated(Permission.MANAGE_SETTINGS),
|
||||
@@ -29,12 +34,6 @@ router.use('/tv', isAuthenticated(), tvRoutes);
|
||||
router.use('/media', isAuthenticated(), mediaRoutes);
|
||||
router.use('/auth', authRoutes);
|
||||
|
||||
router.get('/settings/public', (_req, res) => {
|
||||
const settings = getSettings();
|
||||
|
||||
return res.status(200).json(settings.public);
|
||||
});
|
||||
|
||||
router.get('/', (_req, res) => {
|
||||
return res.status(200).json({
|
||||
api: 'Overseerr API',
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Router } from 'express';
|
||||
import { getRepository, FindOperator } from 'typeorm';
|
||||
import { getRepository, FindOperator, FindOneOptions } from 'typeorm';
|
||||
import Media from '../entity/Media';
|
||||
import { MediaStatus } from '../constants/media';
|
||||
|
||||
@@ -43,11 +43,21 @@ mediaRoutes.get('/', async (req, res, next) => {
|
||||
statusFilter = undefined;
|
||||
}
|
||||
|
||||
let sortFilter: FindOneOptions<Media>['order'] = {
|
||||
id: 'DESC',
|
||||
};
|
||||
|
||||
switch (req.query.sort) {
|
||||
case 'modified':
|
||||
sortFilter = {
|
||||
updatedAt: 'DESC',
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
const [media, mediaCount] = await mediaRepository.findAndCount({
|
||||
order: {
|
||||
id: 'DESC',
|
||||
},
|
||||
order: sortFilter,
|
||||
where: {
|
||||
status: statusFilter,
|
||||
},
|
||||
|
@@ -13,6 +13,8 @@ import SonarrAPI from '../api/sonarr';
|
||||
import RadarrAPI from '../api/radarr';
|
||||
import logger from '../logger';
|
||||
import { scheduledJobs } from '../job/schedule';
|
||||
import { Permission } from '../lib/permissions';
|
||||
import { isAuthenticated } from '../middleware/auth';
|
||||
|
||||
const settingsRoutes = Router();
|
||||
|
||||
@@ -334,4 +336,17 @@ settingsRoutes.get('/jobs', (req, res) => {
|
||||
);
|
||||
});
|
||||
|
||||
settingsRoutes.get(
|
||||
'/initialize',
|
||||
isAuthenticated(Permission.ADMIN),
|
||||
(req, res) => {
|
||||
const settings = getSettings();
|
||||
|
||||
settings.public.initialized = true;
|
||||
settings.save();
|
||||
|
||||
return res.status(200).json(settings.public);
|
||||
}
|
||||
);
|
||||
|
||||
export default settingsRoutes;
|
||||
|
@@ -44,7 +44,7 @@ const Discover: React.FC = () => {
|
||||
);
|
||||
|
||||
const { data: media, error: mediaError } = useSWR<MediaResultsResponse>(
|
||||
'/api/v1/media?filter=available&take=20'
|
||||
'/api/v1/media?filter=available&take=20&sort=modified'
|
||||
);
|
||||
|
||||
const { data: requests, error: requestError } = useSWR<MediaRequest[]>(
|
||||
|
@@ -6,12 +6,33 @@ import SettingsPlex from '../Settings/SettingsPlex';
|
||||
import SettingsServices from '../Settings/SettingsServices';
|
||||
import LoginWithPlex from './LoginWithPlex';
|
||||
import SetupSteps from './SetupSteps';
|
||||
import axios from 'axios';
|
||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
finish: 'Finish Setup',
|
||||
finishing: 'Finishing...',
|
||||
continue: 'Continue',
|
||||
});
|
||||
|
||||
const Setup: React.FC = () => {
|
||||
const [isUpdating, setIsUpdating] = useState(false);
|
||||
const [currentStep, setCurrentStep] = useState(1);
|
||||
const [plexSettingsComplete, setPlexSettingsComplete] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
const finishSetup = async () => {
|
||||
setIsUpdating(false);
|
||||
const response = await axios.get<{ initialized: boolean }>(
|
||||
'/api/v1/settings/initialize'
|
||||
);
|
||||
|
||||
setIsUpdating(false);
|
||||
if (response.data.initialized) {
|
||||
router.push('/');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-cool-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8 relative">
|
||||
<ImageFader
|
||||
@@ -68,7 +89,7 @@ const Setup: React.FC = () => {
|
||||
disabled={!plexSettingsComplete}
|
||||
onClick={() => setCurrentStep(3)}
|
||||
>
|
||||
Continue
|
||||
<FormattedMessage {...messages.continue} />
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
@@ -83,9 +104,14 @@ const Setup: React.FC = () => {
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<Button
|
||||
buttonType="primary"
|
||||
onClick={() => router.push('/')}
|
||||
onClick={() => finishSetup()}
|
||||
disabled={isUpdating}
|
||||
>
|
||||
Finish Setup
|
||||
{isUpdating ? (
|
||||
<FormattedMessage {...messages.finishing} />
|
||||
) : (
|
||||
<FormattedMessage {...messages.finish} />
|
||||
)}
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
|
@@ -96,29 +96,47 @@ CoreApp.getInitialProps = async (initialProps) => {
|
||||
let locale = 'en';
|
||||
|
||||
if (ctx.res) {
|
||||
try {
|
||||
// Attempt to get the user by running a request to the local api
|
||||
const response = await axios.get<User>(
|
||||
`http://localhost:${process.env.PORT || 3000}/api/v1/auth/me`,
|
||||
{ headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined }
|
||||
);
|
||||
user = response.data;
|
||||
// Check if app is initialized and redirect if necessary
|
||||
let initialized = true;
|
||||
|
||||
if (router.pathname.match(/login/)) {
|
||||
const response = await axios.get<{ initialized: boolean }>(
|
||||
`http://localhost:${process.env.PORT || 3000}/api/v1/settings/public`
|
||||
);
|
||||
|
||||
initialized = response.data.initialized;
|
||||
|
||||
if (!initialized) {
|
||||
if (!router.pathname.match(/(setup|login\/plex)/)) {
|
||||
ctx.res.writeHead(307, {
|
||||
Location: '/',
|
||||
Location: '/setup',
|
||||
});
|
||||
ctx.res.end();
|
||||
}
|
||||
} catch (e) {
|
||||
// If there is no user, and ctx.res is set (to check if we are on the server side)
|
||||
// _AND_ we are not already on the login or setup route, redirect to /login with a 307
|
||||
// before anything actually renders
|
||||
if (!router.pathname.match(/(login|setup)/)) {
|
||||
ctx.res.writeHead(307, {
|
||||
Location: '/login',
|
||||
});
|
||||
ctx.res.end();
|
||||
} else {
|
||||
try {
|
||||
// Attempt to get the user by running a request to the local api
|
||||
const response = await axios.get<User>(
|
||||
`http://localhost:${process.env.PORT || 3000}/api/v1/auth/me`,
|
||||
{ headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined }
|
||||
);
|
||||
user = response.data;
|
||||
|
||||
if (router.pathname.match(/login/)) {
|
||||
ctx.res.writeHead(307, {
|
||||
Location: '/',
|
||||
});
|
||||
ctx.res.end();
|
||||
}
|
||||
} catch (e) {
|
||||
// If there is no user, and ctx.res is set (to check if we are on the server side)
|
||||
// _AND_ we are not already on the login or setup route, redirect to /login with a 307
|
||||
// before anything actually renders
|
||||
if (!router.pathname.match(/(login|setup)/)) {
|
||||
ctx.res.writeHead(307, {
|
||||
Location: '/login',
|
||||
});
|
||||
ctx.res.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user