From 0eea1b1ff4c0a80d971bd8ece48615bb613a1ea3 Mon Sep 17 00:00:00 2001 From: code002lover Date: Sun, 11 Jan 2026 19:13:56 +0100 Subject: [PATCH] add refresh state from file --- backend/src/main.rs | 26 ++++++++++++ frontend/items.ts | 81 +++++++++++++++++++++++++++++++++++++ frontend/src/App.tsx | 2 +- frontend/src/PersonList.tsx | 62 +++++++++++++++++++++++++++- frontend/src/api.ts | 6 +++ protobuf/items.proto | 5 +++ 6 files changed, 179 insertions(+), 3 deletions(-) diff --git a/backend/src/main.rs b/backend/src/main.rs index 7b63aaf..0142a6f 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -160,6 +160,31 @@ async fn delete_game( None } +#[post("/refresh")] +async fn refresh_state( + _token: auth::AdminToken, + game_list: &rocket::State>>, + user_list: &rocket::State>>, +) -> items::RefreshResponse { + if let Some((new_games, new_users)) = store::load_state() { + let mut games = game_list.lock().await; + let mut users = user_list.lock().await; + + *games = new_games; + *users = new_users; + + items::RefreshResponse { + success: true, + message: "State refreshed from file".to_string(), + } + } else { + items::RefreshResponse { + success: false, + message: "Failed to load state from file".to_string(), + } + } +} + #[post("/opinion", data = "")] async fn add_opinion( token: auth::Token, @@ -405,6 +430,7 @@ async fn main() -> Result<(), std::io::Error> { add_game, update_game, delete_game, + refresh_state, get_game_thumbnail, get_games_batch ], diff --git a/frontend/items.ts b/frontend/items.ts index 414cbc7..dfb385f 100644 --- a/frontend/items.ts +++ b/frontend/items.ts @@ -90,6 +90,11 @@ export interface LogoutResponse { message: string; } +export interface RefreshResponse { + success: boolean; + message: string; +} + export interface AuthStatusRequest { token: string; } @@ -837,6 +842,82 @@ export const LogoutResponse: MessageFns = { }, }; +function createBaseRefreshResponse(): RefreshResponse { + return { success: false, message: "" }; +} + +export const RefreshResponse: MessageFns = { + encode(message: RefreshResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.success !== false) { + writer.uint32(8).bool(message.success); + } + if (message.message !== "") { + writer.uint32(18).string(message.message); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): RefreshResponse { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseRefreshResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.success = reader.bool(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.message = reader.string(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): RefreshResponse { + return { + success: isSet(object.success) ? globalThis.Boolean(object.success) : false, + message: isSet(object.message) ? globalThis.String(object.message) : "", + }; + }, + + toJSON(message: RefreshResponse): unknown { + const obj: any = {}; + if (message.success !== false) { + obj.success = message.success; + } + if (message.message !== "") { + obj.message = message.message; + } + return obj; + }, + + create, I>>(base?: I): RefreshResponse { + return RefreshResponse.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): RefreshResponse { + const message = createBaseRefreshResponse(); + message.success = object.success ?? false; + message.message = object.message ?? ""; + return message; + }, +}; + function createBaseAuthStatusRequest(): AuthStatusRequest { return { token: "" }; } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 24a46fa..2c168e2 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -172,7 +172,7 @@ function App() { - } /> + } /> } /> } /> } /> diff --git a/frontend/src/PersonList.tsx b/frontend/src/PersonList.tsx index 4c0a6c7..54d164a 100644 --- a/frontend/src/PersonList.tsx +++ b/frontend/src/PersonList.tsx @@ -1,20 +1,41 @@ import { Person } from "../items"; import { Link } from "react-router-dom"; import { useState } from "react"; -import { get_auth_status } from "./api"; +import { get_auth_status, refresh_state, get_is_admin } from "./api"; +import type { ToastType } from "./Toast"; import "./PersonList.css" interface Props { people: Person[]; + onShowToast?: (message: string, type?: ToastType) => void; } -export const PersonList = ({ people }: Props) => { +export const PersonList = ({ people, onShowToast }: Props) => { const [current_user, set_current_user] = useState(""); + const [isRefreshing, setIsRefreshing] = useState(false); + get_auth_status().then((res) => { if (res) { set_current_user(res.username); } }); + + const handleRefresh = async () => { + setIsRefreshing(true); + try { + await refresh_state(); + onShowToast?.("State refreshed from file successfully", "success"); + window.location.reload(); + } catch (err) { + console.error(err); + onShowToast?.("Failed to refresh state from file", "error"); + } finally { + setIsRefreshing(false); + } + }; + + const isAdmin = get_is_admin(); + return (
{ }} >

People List

+ {isAdmin && ( + + )}
{people.map((person, index) => { diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 18dad73..6ca4d88 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -55,3 +55,9 @@ export const get_auth_status = async (): Promise => { export const get_is_admin = (): boolean => { return localStorage.getItem("isAdmin") === "true"; }; + +export const refresh_state = async (): Promise => { + await apiFetch("/api/refresh", { + method: "POST", + }); +}; diff --git a/protobuf/items.proto b/protobuf/items.proto index 6729cf9..9c00d2a 100644 --- a/protobuf/items.proto +++ b/protobuf/items.proto @@ -50,6 +50,11 @@ message LogoutResponse { string message = 2; } +message RefreshResponse { + bool success = 1; + string message = 2; +} + message AuthStatusRequest { string token = 1; } message AuthStatusResponse {