mirror of
https://github.com/idanoo/autobrr
synced 2025-07-26 02:09:13 +00:00
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:
parent
2e8d0950c1
commit
40b855bf39
56 changed files with 1208 additions and 257 deletions
104
web/src/screens/auth/login.tsx
Normal file
104
web/src/screens/auth/login.tsx
Normal file
|
@ -0,0 +1,104 @@
|
|||
import {useMutation} from "react-query";
|
||||
import APIClient from "../../api/APIClient";
|
||||
import {Form} from "react-final-form";
|
||||
import {PasswordField, TextField} from "../../components/inputs";
|
||||
import {useRecoilState} from "recoil";
|
||||
import {isLoggedIn} from "../../state/state";
|
||||
import {useHistory} from "react-router-dom";
|
||||
import {useEffect} from "react";
|
||||
import logo from "../../logo.png"
|
||||
|
||||
interface loginData {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
function Login() {
|
||||
const [loggedIn, setLoggedIn] = useRecoilState(isLoggedIn);
|
||||
let history = useHistory();
|
||||
|
||||
useEffect(() => {
|
||||
if(loggedIn) {
|
||||
// setLoading(false);
|
||||
history.push('/');
|
||||
} else {
|
||||
// setLoading(false);
|
||||
}
|
||||
}, [loggedIn, history])
|
||||
|
||||
const mutation = useMutation((data: loginData) => APIClient.auth.login(data.username, data.password), {
|
||||
onSuccess: () => {
|
||||
setLoggedIn(true);
|
||||
},
|
||||
})
|
||||
|
||||
const onSubmit = (data: any, form: any) => {
|
||||
mutation.mutate(data)
|
||||
form.reset()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md mb-6">
|
||||
<img
|
||||
className="mx-auto h-12 w-auto"
|
||||
src={logo}
|
||||
alt="logo"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
|
||||
|
||||
<Form
|
||||
initialValues={{
|
||||
username: "",
|
||||
password: "",
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
{({handleSubmit, values}) => {
|
||||
return (
|
||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||
<TextField name="username" label="Username" autoComplete="username" />
|
||||
<PasswordField name="password" label="password" autoComplete="current-password"/>
|
||||
|
||||
{/*<div className="flex items-center justify-between">*/}
|
||||
{/* <div className="flex items-center">*/}
|
||||
{/* <input*/}
|
||||
{/* id="remember-me"*/}
|
||||
{/* name="remember-me"*/}
|
||||
{/* type="checkbox"*/}
|
||||
{/* className="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"*/}
|
||||
{/* />*/}
|
||||
{/* <label htmlFor="remember-me" className="ml-2 block text-sm text-gray-900">*/}
|
||||
{/* Remember me*/}
|
||||
{/* </label>*/}
|
||||
{/* </div>*/}
|
||||
|
||||
{/* <div className="text-sm">*/}
|
||||
{/* <a href="#" className="font-medium text-indigo-600 hover:text-indigo-500">*/}
|
||||
{/* Forgot your password?*/}
|
||||
{/* </a>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Sign in
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}}
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Login;
|
29
web/src/screens/auth/logout.tsx
Normal file
29
web/src/screens/auth/logout.tsx
Normal file
|
@ -0,0 +1,29 @@
|
|||
import APIClient from "../../api/APIClient";
|
||||
import {useRecoilState} from "recoil";
|
||||
import {isLoggedIn} from "../../state/state";
|
||||
import {useEffect} from "react";
|
||||
import {useCookies} from "react-cookie";
|
||||
import {useHistory} from "react-router-dom";
|
||||
|
||||
function Logout() {
|
||||
const [loggedIn, setLoggedIn] = useRecoilState(isLoggedIn);
|
||||
let history = useHistory();
|
||||
|
||||
const [_, removeCookie] = useCookies(['user_session']);
|
||||
|
||||
useEffect(() => {
|
||||
APIClient.auth.logout().then(r => {
|
||||
removeCookie("user_session", "")
|
||||
setLoggedIn(false);
|
||||
history.push('/login');
|
||||
})
|
||||
}, [loggedIn, history, removeCookie, setLoggedIn])
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<p>Logged out</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Logout;
|
Loading…
Add table
Add a link
Reference in a new issue