mirror of
https://github.com/Radiquum/AniX.git
synced 2025-04-08 17:24:39 +00:00
Back and Front: User Login
This commit is contained in:
parent
a03deddbc0
commit
32a4da1a31
8 changed files with 141 additions and 36 deletions
|
@ -1,20 +1,21 @@
|
|||
from typing import Annotated
|
||||
|
||||
import requests
|
||||
from fastapi import APIRouter
|
||||
from fastapi import Form
|
||||
from fastapi import Request
|
||||
from modules.proxy import ENDPOINTS
|
||||
from modules.proxy import USER_AGENT
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
email: str
|
||||
password: str
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("", summary="logging in")
|
||||
async def userSignIn(
|
||||
request: Request,
|
||||
email: Annotated[str, Form()],
|
||||
password: Annotated[str, Form()],
|
||||
user: User,
|
||||
short: bool = False,
|
||||
):
|
||||
headers = {
|
||||
|
@ -26,7 +27,7 @@ async def userSignIn(
|
|||
# noqa: E501
|
||||
f"{ENDPOINTS['auth']}",
|
||||
headers=headers,
|
||||
data={"login": email, "password": password},
|
||||
data={"login": user.email, "password": user.password},
|
||||
)
|
||||
if r.status_code != 200:
|
||||
return {"error": r.text}
|
||||
|
|
|
@ -5,23 +5,25 @@ import "material-dynamic-colors";
|
|||
import { NavigationRail } from "@/app/components/NavigationRail/NavigationRail";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ColorPicker } from "@/app/components/ColorPicker/ColorPicker";
|
||||
import { useUserStore } from "./store/user-store";
|
||||
|
||||
export function setMode(mode) {
|
||||
function setMode(mode) {
|
||||
localStorage.setItem("mode", mode);
|
||||
}
|
||||
export function getMode() {
|
||||
function getMode() {
|
||||
return localStorage.getItem("mode");
|
||||
}
|
||||
|
||||
export function setTheme(theme) {
|
||||
function setTheme(theme) {
|
||||
localStorage.setItem("theme", theme);
|
||||
}
|
||||
export function getTheme() {
|
||||
function getTheme() {
|
||||
return localStorage.getItem("theme");
|
||||
}
|
||||
|
||||
export const App = (props) => {
|
||||
const [colorPicker, setColorPicker] = useState(false);
|
||||
const userStore = useUserStore();
|
||||
|
||||
const theme = async (from) => {
|
||||
setTheme(from);
|
||||
|
@ -45,6 +47,11 @@ export const App = (props) => {
|
|||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
userStore.checkAuth();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<body>
|
||||
<div>
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
export const isResponseOk = (response) => {
|
||||
return !(response instanceof Error);
|
||||
};
|
||||
|
||||
export const getData = async (url) => {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
|
@ -14,8 +18,8 @@ export const authorize = async (url, data) => {
|
|||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: data,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (response.status !== 200) {
|
||||
throw new Error("Ошибка получения данных");
|
||||
|
@ -28,7 +32,7 @@ export const authorize = async (url, data) => {
|
|||
|
||||
export const getMe = async (url, jwt) => {
|
||||
try {
|
||||
const response = await fetch(`${url}?token=${jwt}&short=True`, {
|
||||
const response = await fetch(`${url}?token=${jwt}`, {
|
||||
method: "GET",
|
||||
});
|
||||
if (response.status !== 200) {
|
||||
|
@ -40,12 +44,14 @@ export const getMe = async (url, jwt) => {
|
|||
}
|
||||
};
|
||||
|
||||
export function setJWT(jwt) {
|
||||
localStorage.setItem("jwt", jwt);
|
||||
export function setJWT(jwt, user_id) {
|
||||
const data = { jwt: jwt, user_id: user_id };
|
||||
localStorage.setItem("data", JSON.stringify(data));
|
||||
}
|
||||
export function getJWT() {
|
||||
return localStorage.getItem("jwt");
|
||||
const data = localStorage.getItem("data");
|
||||
return JSON.parse(data);
|
||||
}
|
||||
export function removeJWT() {
|
||||
localStorage.removeItem("jwt");
|
||||
localStorage.removeItem("data");
|
||||
}
|
||||
|
|
|
@ -8,4 +8,8 @@ export const endpoints = {
|
|||
finished: `${API_URL}/index/finished`,
|
||||
},
|
||||
search: `${API_URL}/search`,
|
||||
user: {
|
||||
profile: `${API_URL}/profile`,
|
||||
auth: `${API_URL}/auth`,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,9 +3,13 @@
|
|||
import { usePathname } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { useUserStore } from "@/app/store/user-store";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export const NavigationRail = (props) => {
|
||||
const pathname = usePathname();
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
|
||||
const items = [
|
||||
{
|
||||
|
@ -37,15 +41,26 @@ export const NavigationRail = (props) => {
|
|||
|
||||
return (
|
||||
<nav className="left">
|
||||
<button className="circle transparent ">
|
||||
<Image
|
||||
className="responsive"
|
||||
src="/favicon.ico"
|
||||
alt="Ваш профиль"
|
||||
width="64"
|
||||
height="64"
|
||||
/>
|
||||
</button>
|
||||
{userStore.isAuth && userStore.user ? (
|
||||
<Link className="circle transparent " href="/profile">
|
||||
<Image
|
||||
className="responsive"
|
||||
src={userStore.user.profile.avatar}
|
||||
alt="Ваш профиль"
|
||||
width="64"
|
||||
height="64"
|
||||
/>
|
||||
</Link>
|
||||
) : (
|
||||
<button
|
||||
className="circle transparent"
|
||||
onClick={() => {
|
||||
router.push("/login");
|
||||
}}
|
||||
>
|
||||
<i className="responsive">login</i>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{items.map((item) => {
|
||||
return (
|
||||
|
@ -67,6 +82,17 @@ export const NavigationRail = (props) => {
|
|||
>
|
||||
<i>palette</i>
|
||||
</button>
|
||||
|
||||
{userStore.isAuth ? (
|
||||
<button
|
||||
className="circle transparent"
|
||||
onClick={() => userStore.logout()}
|
||||
>
|
||||
<i>logout</i>
|
||||
</button>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -24,8 +24,8 @@ export const ReleaseCard = (props) => {
|
|||
<h6>{`${props.title.substring(0, 30)}${
|
||||
[...props.title].length > 30 ? "..." : ""
|
||||
}`}</h6>
|
||||
<p>{`${props.description}${
|
||||
[...props.description].length > 160 ? "..." : ""
|
||||
<p>{`${props.description.substring(0, 150)}${
|
||||
[...props.description].length > 150 ? "..." : ""
|
||||
}`}</p>
|
||||
</div>
|
||||
</article>
|
||||
|
|
|
@ -1,3 +1,60 @@
|
|||
"use client";
|
||||
|
||||
import { useUserStore } from "../store/user-store";
|
||||
import { endpoints } from "../api/config";
|
||||
import { authorize, isResponseOk } from "../api/api-utils";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
export default function LoginPage() {
|
||||
return <p>login page</p>;
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
const [authData, setAuthData] = useState({ email: "", password: "" });
|
||||
|
||||
const handleInput = (e) => {
|
||||
setAuthData({ ...authData, [e.target.name]: e.target.value });
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const userData = await authorize(endpoints.user.auth, authData);
|
||||
if (isResponseOk(userData)) {
|
||||
userStore.login(
|
||||
userData,
|
||||
userData.profileToken.token,
|
||||
userData.profile.id,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let timer;
|
||||
if (userStore.user) {
|
||||
timer = setTimeout(() => {
|
||||
router.push("/profile");
|
||||
}, 1000);
|
||||
}
|
||||
return () => clearTimeout(timer);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [userStore.user]);
|
||||
|
||||
return (
|
||||
<div className="absolute padding tertiary center middle round">
|
||||
<i className="extra">login</i>
|
||||
<h5>Вход в аккаунт anixart.</h5>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="border field fill label large round">
|
||||
<input type="email" name="email" onInput={handleInput} />
|
||||
<label>логин</label>
|
||||
</div>
|
||||
<div className="border field fill label large round">
|
||||
<input type="password" name="password" onInput={handleInput} />
|
||||
<label>пароль</label>
|
||||
</div>
|
||||
<button className="small-round medium" type="submit">
|
||||
<i>login</i>
|
||||
<span>Войти</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,20 +7,24 @@ export const useUserStore = create((set, get) => ({
|
|||
isAuth: false,
|
||||
user: null,
|
||||
token: null,
|
||||
login: (user, token) => {
|
||||
|
||||
login: (user, token, user_id) => {
|
||||
set({ isAuth: true, user, token });
|
||||
setJWT(token);
|
||||
setJWT(token, user_id);
|
||||
},
|
||||
logout: () => {
|
||||
set({ isAuth: false, user: null, token: null });
|
||||
removeJWT();
|
||||
},
|
||||
checkAuth: async (user_id) => {
|
||||
checkAuth: async () => {
|
||||
const jwt = getJWT();
|
||||
if (jwt) {
|
||||
const me = await getMe(`${endpoints.profile}/${user_id}`, jwt);
|
||||
const me = await getMe(
|
||||
`${endpoints.user.profile}/${jwt.user_id}`,
|
||||
jwt.jwt,
|
||||
);
|
||||
if (me.is_my_profile) {
|
||||
get().login(me, jwt);
|
||||
get().login(me, jwt.jwt, jwt.user_id);
|
||||
} else {
|
||||
get().logout();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue