feat: force setup if app is not initialized

pull/175/head
sct 4 years ago
parent c0ce87b6f6
commit a99705f6a5

@ -1160,6 +1160,7 @@ paths:
/settings/public: /settings/public:
get: get:
summary: Returns public settings 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. description: Returns settings that are not protected or sensitive. Mainly used to determine if the app has been configured for the first time.
tags: tags:
- settings - settings
@ -1170,6 +1171,19 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PublicSettings' $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: /settings/jobs:
get: get:
summary: Returns list of scheduled jobs summary: Returns list of scheduled jobs
@ -1887,6 +1901,12 @@ paths:
type: string type: string
nullable: true nullable: true
enum: [all, available, partial, processing, pending] enum: [all, available, partial, processing, pending]
- in: query
name: sort
schema:
type: string
enum: [added, modified]
default: added
responses: responses:
'200': '200':
description: Returned media description: Returned media

@ -16,6 +16,11 @@ const router = Router();
router.use(checkUser); router.use(checkUser);
router.use('/user', isAuthenticated(Permission.MANAGE_USERS), user); 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( router.use(
'/settings', '/settings',
isAuthenticated(Permission.MANAGE_SETTINGS), isAuthenticated(Permission.MANAGE_SETTINGS),
@ -29,12 +34,6 @@ router.use('/tv', isAuthenticated(), tvRoutes);
router.use('/media', isAuthenticated(), mediaRoutes); router.use('/media', isAuthenticated(), mediaRoutes);
router.use('/auth', authRoutes); router.use('/auth', authRoutes);
router.get('/settings/public', (_req, res) => {
const settings = getSettings();
return res.status(200).json(settings.public);
});
router.get('/', (_req, res) => { router.get('/', (_req, res) => {
return res.status(200).json({ return res.status(200).json({
api: 'Overseerr API', api: 'Overseerr API',

@ -1,5 +1,5 @@
import { Router } from 'express'; import { Router } from 'express';
import { getRepository, FindOperator } from 'typeorm'; import { getRepository, FindOperator, FindOneOptions } from 'typeorm';
import Media from '../entity/Media'; import Media from '../entity/Media';
import { MediaStatus } from '../constants/media'; import { MediaStatus } from '../constants/media';
@ -43,11 +43,21 @@ mediaRoutes.get('/', async (req, res, next) => {
statusFilter = undefined; statusFilter = undefined;
} }
let sortFilter: FindOneOptions<Media>['order'] = {
id: 'DESC',
};
switch (req.query.sort) {
case 'modified':
sortFilter = {
updatedAt: 'DESC',
};
break;
}
try { try {
const [media, mediaCount] = await mediaRepository.findAndCount({ const [media, mediaCount] = await mediaRepository.findAndCount({
order: { order: sortFilter,
id: 'DESC',
},
where: { where: {
status: statusFilter, status: statusFilter,
}, },

@ -13,6 +13,8 @@ import SonarrAPI from '../api/sonarr';
import RadarrAPI from '../api/radarr'; import RadarrAPI from '../api/radarr';
import logger from '../logger'; import logger from '../logger';
import { scheduledJobs } from '../job/schedule'; import { scheduledJobs } from '../job/schedule';
import { Permission } from '../lib/permissions';
import { isAuthenticated } from '../middleware/auth';
const settingsRoutes = Router(); 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; export default settingsRoutes;

@ -44,7 +44,7 @@ const Discover: React.FC = () => {
); );
const { data: media, error: mediaError } = useSWR<MediaResultsResponse>( 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[]>( const { data: requests, error: requestError } = useSWR<MediaRequest[]>(

@ -6,12 +6,33 @@ import SettingsPlex from '../Settings/SettingsPlex';
import SettingsServices from '../Settings/SettingsServices'; import SettingsServices from '../Settings/SettingsServices';
import LoginWithPlex from './LoginWithPlex'; import LoginWithPlex from './LoginWithPlex';
import SetupSteps from './SetupSteps'; 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 Setup: React.FC = () => {
const [isUpdating, setIsUpdating] = useState(false);
const [currentStep, setCurrentStep] = useState(1); const [currentStep, setCurrentStep] = useState(1);
const [plexSettingsComplete, setPlexSettingsComplete] = useState(false); const [plexSettingsComplete, setPlexSettingsComplete] = useState(false);
const router = useRouter(); 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 ( return (
<div className="min-h-screen bg-cool-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8 relative"> <div className="min-h-screen bg-cool-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8 relative">
<ImageFader <ImageFader
@ -68,7 +89,7 @@ const Setup: React.FC = () => {
disabled={!plexSettingsComplete} disabled={!plexSettingsComplete}
onClick={() => setCurrentStep(3)} onClick={() => setCurrentStep(3)}
> >
Continue <FormattedMessage {...messages.continue} />
</Button> </Button>
</span> </span>
</div> </div>
@ -83,9 +104,14 @@ const Setup: React.FC = () => {
<span className="ml-3 inline-flex rounded-md shadow-sm"> <span className="ml-3 inline-flex rounded-md shadow-sm">
<Button <Button
buttonType="primary" buttonType="primary"
onClick={() => router.push('/')} onClick={() => finishSetup()}
disabled={isUpdating}
> >
Finish Setup {isUpdating ? (
<FormattedMessage {...messages.finishing} />
) : (
<FormattedMessage {...messages.finish} />
)}
</Button> </Button>
</span> </span>
</div> </div>

@ -96,29 +96,47 @@ CoreApp.getInitialProps = async (initialProps) => {
let locale = 'en'; let locale = 'en';
if (ctx.res) { if (ctx.res) {
try { // Check if app is initialized and redirect if necessary
// Attempt to get the user by running a request to the local api let initialized = true;
const response = await axios.get<User>(
`http://localhost:${process.env.PORT || 3000}/api/v1/auth/me`, const response = await axios.get<{ initialized: boolean }>(
{ headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined } `http://localhost:${process.env.PORT || 3000}/api/v1/settings/public`
); );
user = response.data;
initialized = response.data.initialized;
if (router.pathname.match(/login/)) {
if (!initialized) {
if (!router.pathname.match(/(setup|login\/plex)/)) {
ctx.res.writeHead(307, { ctx.res.writeHead(307, {
Location: '/', Location: '/setup',
}); });
ctx.res.end(); ctx.res.end();
} }
} catch (e) { } else {
// If there is no user, and ctx.res is set (to check if we are on the server side) try {
// _AND_ we are not already on the login or setup route, redirect to /login with a 307 // Attempt to get the user by running a request to the local api
// before anything actually renders const response = await axios.get<User>(
if (!router.pathname.match(/(login|setup)/)) { `http://localhost:${process.env.PORT || 3000}/api/v1/auth/me`,
ctx.res.writeHead(307, { { headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined }
Location: '/login', );
}); user = response.data;
ctx.res.end();
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();
}
} }
} }

Loading…
Cancel
Save