Feature: Auth (#4)

* feat(api): add auth

* feat(web): add auth and refactor

* refactor(web): baseurl

* feat: add autobrrctl cli for user creation

* build: move static assets

* refactor(web): auth guard and routing

* refactor: rename var

* fix: remove subrouter

* build: update default config
This commit is contained in:
Ludvig Lundgren 2021-08-14 14:19:21 +02:00 committed by GitHub
parent 2e8d0950c1
commit 40b855bf39
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 1208 additions and 257 deletions

View file

@ -5,11 +5,11 @@ import {classNames} from "../styles/utils";
import {CheckIcon, ChevronRightIcon, ExclamationIcon, SelectorIcon,} from "@heroicons/react/solid";
import {useToggle} from "../hooks/hooks";
import {useMutation} from "react-query";
import {queryClient} from "..";
import {Field, Form} from "react-final-form";
import {TextField} from "./inputs";
import DEBUG from "./debug";
import APIClient from "../api/APIClient";
import {queryClient} from "../App";
interface radioFieldsetOption {
label: string;

View file

@ -0,0 +1,38 @@
import {isLoggedIn} from "../state/state";
import {useRecoilState} from "recoil";
import {useEffect, useState} from "react";
import { Fragment } from "react";
import {Redirect} from "react-router-dom";
import APIClient from "../api/APIClient";
export default function Layout({auth=false, authFallback="/login", children}: any) {
const [loggedIn, setLoggedIn] = useRecoilState(isLoggedIn);
const [loading, setLoading] = useState(auth);
useEffect(() => {
// check token
APIClient.auth.test()
.then(r => {
setLoggedIn(true);
setLoading(false);
})
.catch(a => {
setLoading(false);
})
}, [setLoggedIn])
return (
<Fragment>
{loading ? null : (
<Fragment>
{auth && !loggedIn ? <Redirect to={authFallback} /> : (
<Fragment>
{children}
</Fragment>
)}
</Fragment>
)}
</Fragment>
)
}

View file

@ -0,0 +1,47 @@
import { Field } from "react-final-form";
import React from "react";
import Error from "./Error";
import {classNames} from "../../styles/utils";
type COL_WIDTHS = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
interface Props {
name: string;
label?: string;
placeholder?: string;
columns?: COL_WIDTHS;
className?: string;
autoComplete?: string;
}
const PasswordField: React.FC<Props> = ({ name, label, placeholder, columns , className, autoComplete}) => (
<div
className={classNames(
columns ? `col-span-${columns}` : "col-span-12"
)}
>
{label && (
<label htmlFor={name} className="block text-xs font-bold text-gray-700 uppercase tracking-wide">
{label}
</label>
)}
<Field
name={name}
render={({input, meta}) => (
<input
{...input}
id={name}
type="password"
autoComplete={autoComplete}
className="mt-2 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-light-blue-500 focus:border-light-blue-500 sm:text-sm"
placeholder={placeholder}
/>
)}
/>
<div>
<Error name={name} classNames="text-red mt-2" />
</div>
</div>
)
export default PasswordField;

View file

@ -11,9 +11,10 @@ interface Props {
placeholder?: string;
columns?: COL_WIDTHS;
className?: string;
autoComplete?: string;
}
const TextField: React.FC<Props> = ({ name, label, placeholder, columns , className}) => (
const TextField: React.FC<Props> = ({ name, label, placeholder, columns , className, autoComplete}) => (
<div
className={classNames(
columns ? `col-span-${columns}` : "col-span-12"
@ -31,6 +32,7 @@ const TextField: React.FC<Props> = ({ name, label, placeholder, columns , classN
{...input}
id={name}
type="text"
autoComplete={autoComplete}
className="mt-2 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-light-blue-500 focus:border-light-blue-500 sm:text-sm"
placeholder={placeholder}
/>

View file

@ -1,5 +1,6 @@
export { default as TextField } from "./TextField";
export { default as TextFieldWide } from "./TextFieldWide";
export { default as PasswordField } from "./PasswordField";
export { default as TextAreaWide } from "./TextAreaWide";
export { default as MultiSelectField } from "./MultiSelectField";
export { default as RadioFieldset } from "./RadioFieldset";