diff --git a/main.py b/main.py
index 4fee76b..7ce4c5a 100644
--- a/main.py
+++ b/main.py
@@ -59,7 +59,7 @@ def add_players(players: list[Player]):
session.commit()
-def list_players():
+async def list_players():
with Session(engine) as session:
statement = select(Player).order_by(Player.display_name)
players = session.exec(statement).fetchall()
@@ -69,6 +69,11 @@ def list_players():
]
+async def read_teams_me(user: Annotated[Player, Depends(get_current_active_user)]):
+ with Session(engine) as session:
+ return [p.teams for p in session.exec(select(P).where(P.id == user.id))][0]
+
+
def list_teams():
with Session(engine) as session:
statement = select(Team)
@@ -79,12 +84,16 @@ player_router = APIRouter(prefix="/player")
player_router.add_api_route("/list", endpoint=list_players, methods=["GET"])
player_router.add_api_route("/add", endpoint=add_player, methods=["POST"])
player_router.add_api_route("/me", endpoint=read_player_me, methods=["GET"])
+player_router.add_api_route("/me/teams", endpoint=read_teams_me, methods=["GET"])
player_router.add_api_route("/me/items", endpoint=read_own_items, methods=["GET"])
player_router.add_api_route(
"/change_password", endpoint=change_password, methods=["POST"]
)
-team_router = APIRouter(prefix="/team")
+team_router = APIRouter(
+ prefix="/team",
+ dependencies=[Security(get_current_active_user, scopes=["admin"])],
+)
team_router.add_api_route("/list", endpoint=list_teams, methods=["GET"])
team_router.add_api_route("/add", endpoint=add_team, methods=["POST"])
diff --git a/security.py b/security.py
index aa574bd..5ad8bb7 100644
--- a/security.py
+++ b/security.py
@@ -60,6 +60,7 @@ oauth2_scheme = CookieOAuth2(
tokenUrl="api/token",
scopes={
"analysis": "Access the results.",
+ "admin": "Maintain DB etc.",
},
)
diff --git a/src/App.css b/src/App.css
index f65621f..435b940 100644
--- a/src/App.css
+++ b/src/App.css
@@ -421,7 +421,7 @@ button {
.user-info {
display: grid;
- grid-template-columns: 1fr 1fr;
+ grid-template-columns: 8em 12em;
gap: 2px 16px;
div {
diff --git a/src/Avatar.tsx b/src/Avatar.tsx
index f1d53a1..58d9488 100644
--- a/src/Avatar.tsx
+++ b/src/Avatar.tsx
@@ -4,13 +4,14 @@ import { User } from "./api";
import { useTheme } from "./ThemeProvider";
import { colourTheme, darkTheme, normalTheme, rainbowTheme } from "./themes";
import { useNavigate } from "react-router";
+import { Team } from "./types";
interface ContextMenuItem {
label: string;
onClick: () => void;
}
-const UserInfo = (user: User) => {
+const UserInfo = (user: User, teams: Team[] | undefined) => {
return (
@@ -24,17 +25,38 @@ const UserInfo = (user: User) => {
number:
-
{user?.number ? user?.number : "-"}
+
{user?.number || "-"}
email:
-
{user?.email ? user?.email : "-"}
+
{user?.email || "-"}
+ {teams && (
+ <>
+
+ teams:
+
+
+ {teams.map((team) => (
+ -
+ {team.name} (
+ {team.location || team.country || "location unknown"})
+
+ ))}
+
+ >
+ )}
);
};
export default function Avatar() {
- const { user, onLogout } = useSession();
+ const { user, teams, onLogout } = useSession();
const { theme, setTheme } = useTheme();
const navigate = useNavigate();
const [contextMenu, setContextMenu] = useState<{
@@ -118,9 +140,9 @@ export default function Avatar() {
const dialogRef = createRef
();
function handleViewProfile() {
- if (user) {
+ if (user && teams) {
dialogRef.current?.showModal();
- setDialog(UserInfo(user));
+ setDialog(UserInfo(user, teams));
}
}
diff --git a/src/Session.tsx b/src/Session.tsx
index fa0987a..457212d 100644
--- a/src/Session.tsx
+++ b/src/Session.tsx
@@ -5,9 +5,10 @@ import {
useEffect,
useState,
} from "react";
-import { currentUser, logout, User } from "./api";
+import { apiAuth, currentUser, logout, User } from "./api";
import { Login } from "./Login";
import Header from "./Header";
+import { Team } from "./types";
export interface SessionProviderProps {
children: ReactNode;
@@ -15,11 +16,13 @@ export interface SessionProviderProps {
export interface Session {
user: User | null;
+ teams: Team[] | null;
onLogout: () => void;
}
const sessionContext = createContext({
user: null,
+ teams: null,
onLogout: () => {},
});
@@ -27,6 +30,7 @@ export function SessionProvider(props: SessionProviderProps) {
const { children } = props;
const [user, setUser] = useState(null);
+ const [teams, setTeams] = useState();
const [err, setErr] = useState(null);
const [loading, setLoading] = useState(false);
@@ -44,8 +48,14 @@ export function SessionProvider(props: SessionProviderProps) {
.finally(() => setLoading(false));
}
+ async function loadTeam() {
+ const teams: Team[] = await apiAuth("player/me/teams", null, "GET");
+ if (teams) setTeams(teams);
+ }
+
useEffect(() => {
loadUser();
+ setTimeout(() => loadTeam(), 1500);
}, []);
function onLogin(user: User) {
@@ -77,7 +87,7 @@ export function SessionProvider(props: SessionProviderProps) {
content = ;
} else
content = (
-
+
{children}
);
diff --git a/src/api.ts b/src/api.ts
index 6074927..94588c2 100644
--- a/src/api.ts
+++ b/src/api.ts
@@ -1,4 +1,5 @@
import { useSession } from "./Session";
+import { Team } from "./types";
export const baseUrl = import.meta.env.VITE_BASE_URL as string;
diff --git a/src/types.ts b/src/types.ts
index a0951c9..5633dd4 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -32,3 +32,9 @@ export interface MVPRanking {
user: number;
mvps: number[];
}
+
+export interface Team {
+ name: string;
+ location: string;
+ country: string;
+}