Updated login refresh logic, working on tile grid

This commit is contained in:
Benjamin Sherriff
2023-12-02 23:07:22 -05:00
parent f3c0955cb2
commit c825c73eb4
6 changed files with 116 additions and 74 deletions

View File

@@ -340,6 +340,40 @@ async fn me(auth: JwtAuth) -> HttpResponse {
HttpResponse::Ok().json(auth) HttpResponse::Ok().json(auth)
} }
#[get("/check-session")]
async fn check_session(req: HttpRequest) -> HttpResponse {
// If there is a access_token cookie, check if it is valid
let has_session = match req.cookie("access_token") {
Some(cookie) => {
let access_token = cookie.value().to_string();
let public_key = env::var("ACCESS_TOKEN_PUBLIC_KEY")
.expect("ACCESS_TOKEN_PUBLIC_KEY must be set");
match verify_token(&access_token, &public_key) {
Ok(_) => true,
Err(_) => false
}
},
None => false
};
if !has_session {
// If there is a refresh_token cookie, check if it is valid
match req.cookie("refresh_token") {
Some(cookie) => {
let refresh_token = cookie.value().to_string();
let public_key = env::var("REFRESH_TOKEN_PUBLIC_KEY")
.expect("REFRESH_TOKEN_PUBLIC_KEY must be set");
match verify_token(&refresh_token, &public_key) {
Ok(_) => return HttpResponse::Ok().json(true),
Err(_) => return HttpResponse::Ok().json(false)
};
},
None => return HttpResponse::Ok().json(false)
};
} else {
return HttpResponse::Ok().json(true)
}
}
#[get("/roles")] #[get("/roles")]
async fn roles() -> HttpResponse { async fn roles() -> HttpResponse {
HttpResponse::Ok().json(vec!["admin", "user"]) HttpResponse::Ok().json(vec!["admin", "user"])
@@ -363,5 +397,6 @@ pub fn init_routes(config: &mut web::ServiceConfig) {
.service(logout) .service(logout)
.service(me) .service(me)
.service(roles) .service(roles)
.service(check_session)
); );
} }

View File

@@ -42,6 +42,15 @@ export async function me(): Promise<ResponseAuth | undefined> {
} }
} }
export async function hasSession(): Promise<boolean> {
const response = await getRequest('auth/check-session');
if (response?.status === 200) {
return response?.json();
} else {
return false;
}
}
/** /**
* Refreshes the logged_in cookie every interval. By default, the interval is 14 minutes. * Refreshes the logged_in cookie every interval. By default, the interval is 14 minutes.
* @param interval * @param interval

View File

@@ -1,6 +1,6 @@
'use client'; 'use client';
import { login, register, refreshLoggedIn } from '@/api/auth'; import { login, register } from '@/api/auth';
import { User } from '@/api/auth.types'; import { User } from '@/api/auth.types';
import { import {
Modal, Modal,
@@ -146,7 +146,6 @@ export function HeaderModal({ type, toggle, setUser, setRefreshId }: HeaderModal
const loginResponse = await login(values.email, values.password); const loginResponse = await login(values.email, values.password);
if (loginResponse) { if (loginResponse) {
setUser(loginResponse.user); setUser(loginResponse.user);
setRefreshId(refreshLoggedIn());
onClose(); onClose();
notifications.update({ notifications.update({
id, id,
@@ -222,7 +221,6 @@ export function HeaderModal({ type, toggle, setUser, setRefreshId }: HeaderModal
const response = await login(values.email, values.password); const response = await login(values.email, values.password);
if (response) { if (response) {
setUser(response.user); setUser(response.user);
setRefreshId(refreshLoggedIn());
onClose(); onClose();
} else { } else {
notifications.show({ notifications.show({

View File

@@ -6,7 +6,7 @@ import './header.css';
import { Avatar, Button, Card, Center, FileButton, Grid, Group, Menu, Text, UnstyledButton } from '@mantine/core'; import { Avatar, Button, Card, Center, FileButton, Grid, Group, Menu, Text, UnstyledButton } from '@mantine/core';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { logout, refresh, refreshLoggedIn } from '@/api/auth'; import { hasSession, logout, refresh, refreshLoggedIn } from '@/api/auth';
import { useToggle } from '@mantine/hooks'; import { useToggle } from '@mantine/hooks';
import { HeaderModal } from './HeaderModal'; import { HeaderModal } from './HeaderModal';
import { HeaderItem, headerItems } from './headerItems'; import { HeaderItem, headerItems } from './headerItems';
@@ -14,6 +14,7 @@ import { userState } from '@/state/auth';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { getPicture, setPicture } from '@/api/users'; import { getPicture, setPicture } from '@/api/users';
import { BsChevronDown } from 'react-icons/bs'; import { BsChevronDown } from 'react-icons/bs';
import { User } from '@/api/auth.types';
export default function Header() { export default function Header() {
const pathName = usePathname(); const pathName = usePathname();
@@ -25,23 +26,33 @@ export default function Header() {
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
if (!user || !Cookies.get('logged_in')) { if (!user) {
refresh().then((response) => { hasSession().then((response) => {
if (response) { if (response) {
setRefreshId(refreshLoggedIn()); refresh().then((response) => {
setUser(response.user); if (response) {
if (response.user.profile_picture) { setUser(response.user);
getPicture().then((response) => { updateUser(response.user);
if (response) { }
setProfilePicture(response as File); });
}
});
}
} }
}); });
} }
}, [user]); }, [user]);
function updateUser(user?: User) {
if (!refreshId) {
setRefreshId(refreshLoggedIn());
}
if (user) {
getPicture().then((response) => {
if (response) {
setProfilePicture(response as File);
}
});
}
}
return ( return (
<> <>
<nav className='navbar'> <nav className='navbar'>
@@ -159,6 +170,8 @@ export default function Header() {
await logout(); await logout();
Cookies.remove('logged_in'); Cookies.remove('logged_in');
setUser(undefined); setUser(undefined);
clearInterval(refreshId);
setRefreshId(undefined);
setProfilePicture(null); setProfilePicture(null);
if (refreshId) { if (refreshId) {
clearInterval(refreshId); clearInterval(refreshId);
@@ -196,13 +209,7 @@ export default function Header() {
toggle={toggle} toggle={toggle}
setUser={(u) => { setUser={(u) => {
setUser(u); setUser(u);
if (u.profile_picture) { updateUser(u);
getPicture().then((response) => {
if (response) {
setProfilePicture(response as File);
}
});
}
}} }}
setRefreshId={setRefreshId} setRefreshId={setRefreshId}
/> />

View File

@@ -1,11 +1,10 @@
'use client'; 'use client';
import { Graphics, Stage, Text } from '@pixi/react'; import { Graphics, Stage } from '@pixi/react';
import { Graphics as PixiGraphics } from '@pixi/graphics'; import { Graphics as PixiGraphics } from '@pixi/graphics';
import { MouseEvent, WheelEvent, useCallback, useEffect, useState } from 'react'; import { MouseEvent, WheelEvent, useCallback, useEffect, useState } from 'react';
import TileControls, { EditTool, Tool, defaultColors } from './TileControls'; import TileControls, { EditTool, Tool, defaultColors } from './TileControls';
import { Box } from '@mantine/core'; import { Box } from '@mantine/core';
import { TextStyle } from 'pixi.js';
interface SquareEdit { interface SquareEdit {
x: number; x: number;
@@ -31,24 +30,21 @@ export default function TileGrid() {
const [edits, setEdits] = useState<SquareEdit[]>([]); const [edits, setEdits] = useState<SquareEdit[]>([]);
useEffect(() => { useEffect(() => {
if (window) { // Prevent context menu from appearing on right click
// window.addEventListener( function handleContextmenu(e: any) {
// 'wheel', e.preventDefault()
// (event) => {
// event.preventDefault();
// },
// { passive: false }
// );
// // Disable right click context menu
// window.addEventListener(
// 'contextmenu',
// (event) => {
// event.preventDefault();
// },
// { passive: false }
// );
} }
}, []); document.addEventListener('contextmenu', handleContextmenu)
// Prevent scrollwheel from scrolling page
function handleScroll(e: any) {
e.preventDefault()
}
document.addEventListener('wheel', handleScroll, { passive: false })
return function cleanup() {
document.removeEventListener('contextmenu', handleContextmenu)
document.removeEventListener('wheel', handleScroll)
}
}, [])
const drawGrid = useCallback( const drawGrid = useCallback(
(g: PixiGraphics) => { (g: PixiGraphics) => {
@@ -65,7 +61,7 @@ export default function TileGrid() {
[gridSize, zoom] [gridSize, zoom]
); );
const drawEdits = useCallback( const drawGridEdits = useCallback(
(g: PixiGraphics) => { (g: PixiGraphics) => {
g.clear(); g.clear();
edits.forEach((edit) => { edits.forEach((edit) => {
@@ -77,24 +73,10 @@ export default function TileGrid() {
[edits, zoom] [edits, zoom]
); );
function clickEvent(e: MouseEvent) {
setMouseDown(true);
setLastPosition({ x: e.clientX, y: e.clientY });
if (tool == Tool.ZOOM) {
handleZoom(e.button === 0 ? -100 : 100, e.clientX, e.clientY);
} else if (tool == Tool.EDIT) {
if (editTool === EditTool.SQUARE) {
drawSquare(e.button, e.clientX, e.clientY);
} else if (editTool === EditTool.CIRCLE) {
// handle circle
}
}
}
function drawSquare(button: number, clientX: number, clientY: number) { function drawSquare(button: number, clientX: number, clientY: number) {
// Calculate tile coordinates
const x = Math.floor((clientX - position.x) / (32 * zoom)); const x = Math.floor((clientX - position.x) / (32 * zoom));
const y = Math.floor((clientY - position.y) / (32 * zoom)); // TODO: Fix y offset, currently appears to be 2 tiles down from mouse
const y = Math.floor((clientY - position.y) / (32 * zoom)) - 2;
if (button === 1) { if (button === 1) {
// Add new edit if left mouse button is pressed // Add new edit if left mouse button is pressed
setEdits([...edits, { x, y, color: colors[selectedColor] }]); setEdits([...edits, { x, y, color: colors[selectedColor] }]);
@@ -104,6 +86,20 @@ export default function TileGrid() {
} }
} }
function clickEvent(e: MouseEvent, isMouseDown: boolean) {
setMouseDown(isMouseDown);
setLastPosition({ x: e.clientX, y: e.clientY });
if (isMouseDown) {
if (tool == Tool.ZOOM) {
handleZoom(e.buttons === 1 ? -100 : 100, e.clientX, e.clientY);
} else if (tool == Tool.EDIT && editTool === EditTool.SQUARE) {
drawSquare(e.buttons, e.clientX, e.clientY);
} else if (editTool === EditTool.CIRCLE) {
// handle circle
}
}
}
function moveEvent(e: MouseEvent) { function moveEvent(e: MouseEvent) {
if (mouseDown) { if (mouseDown) {
if (tool == Tool.HAND || e.buttons == 4) { if (tool == Tool.HAND || e.buttons == 4) {
@@ -116,12 +112,10 @@ export default function TileGrid() {
dy = Math.max(dy, -gridSize.height * zoom + height); dy = Math.max(dy, -gridSize.height * zoom + height);
setPosition({ x: dx, y: dy }); setPosition({ x: dx, y: dy });
setLastPosition({ x: e.clientX, y: e.clientY }); setLastPosition({ x: e.clientX, y: e.clientY });
} else if (tool === Tool.EDIT) { } else if (tool === Tool.EDIT && editTool === EditTool.SQUARE) {
if (editTool === EditTool.SQUARE) {
drawSquare(e.buttons, e.clientX, e.clientY); drawSquare(e.buttons, e.clientX, e.clientY);
} else if (editTool === EditTool.CIRCLE) { } else if (tool === Tool.EDIT && editTool === EditTool.CIRCLE) {
// handle circle // handle circle
}
} else if (tool === Tool.TOKEN) { } else if (tool === Tool.TOKEN) {
// handle token // handle token
} }
@@ -141,11 +135,15 @@ export default function TileGrid() {
} }
newZoom = Math.min(newZoom, 3); newZoom = Math.min(newZoom, 3);
newZoom = Math.max(newZoom, 0.6); newZoom = Math.max(newZoom, 0.6);
console.log(newZoom);
setZoom(newZoom); setZoom(newZoom);
// Adjust position to zoom in on mouse position // Adjust position to zoom in on mouse position
const dx = (position.x - clientX) * (newZoom / zoom) + clientX; let dx = (position.x - clientX) * (newZoom / zoom) + clientX;
const dy = (position.y - clientY) * (newZoom / zoom) + clientY; let dy = (position.y - clientY) * (newZoom / zoom) + clientY;
// Prevent coordinates from going out of bounds
dx = Math.min(dx, 0);
dx = Math.max(dx, -gridSize.width * newZoom + width);
dy = Math.min(dy, 0);
dy = Math.max(dy, -gridSize.height * newZoom + height);
setPosition({ x: dx, y: dy }); setPosition({ x: dx, y: dy });
} }
@@ -158,13 +156,13 @@ export default function TileGrid() {
backgroundColor: 0x333333, backgroundColor: 0x333333,
antialias: false antialias: false
}} }}
onMouseDown={(e) => clickEvent(e)} onMouseDown={(e) => clickEvent(e, true)}
onMouseUp={() => setMouseDown(false)} onMouseUp={(e) => clickEvent(e, false)}
onMouseMove={(e) => moveEvent(e)} onMouseMove={(e) => moveEvent(e)}
onWheel={(e) => zoomEvent(e)} onWheel={(e) => zoomEvent(e)}
> >
<Graphics x={position.x} y={position.y} draw={drawGrid} /> <Graphics x={position.x} y={position.y} draw={drawGrid} />
<Graphics x={position.x} y={position.y} draw={drawEdits} /> <Graphics x={position.x} y={position.y} draw={drawGridEdits} />
</Stage> </Stage>
<TileControls <TileControls
tool={tool} tool={tool}

View File

@@ -5,8 +5,3 @@ export const userState = atom({
key: 'userState', key: 'userState',
default: undefined as User | undefined default: undefined as User | undefined
}); });
export const isAuthenticatedState = atom({
key: 'isAuthenticatedState',
default: false
});