diff --git a/front/components/security/AuthProvider.tsx b/front/components/security/AuthProvider.tsx index 44d48fa4..59e4f103 100644 --- a/front/components/security/AuthProvider.tsx +++ b/front/components/security/AuthProvider.tsx @@ -1,8 +1,10 @@ import React, { useEffect } from "react"; import { getRefreshToken, getUserInfo } from "../../services/auth/auth"; +import { useRouter } from "next/router"; export const AuthContext: any = React.createContext({}); +const NON_AUTHENTICATED_ROUTES = ["/login", "/signup"]; export interface Auth { access_token: string; isAuthenticated: boolean; @@ -10,7 +12,9 @@ export interface Auth { isLoading: boolean; } + const AuthProvider = (props: any) => { + const router = useRouter(); const [auth, setAuth] = React.useState({ access_token: "", isAuthenticated: false, userInfo: {}, isLoading: true }); async function checkRefreshToken() { @@ -19,30 +23,35 @@ const AuthProvider = (props: any) => { } async function checkAuth() { - let access_token = await checkRefreshToken(); - let isAuthenticated = false; - let userInfo = {}; - let isLoading = false; + try { + let access_token = await checkRefreshToken(); + let userInfo = {}; + let isLoading = false; + + if (access_token) { + userInfo = await getUserInfo(access_token); + setAuth({ access_token, isAuthenticated: true, userInfo, isLoading }); - if (access_token) { - userInfo = await getUserInfo(access_token); - isAuthenticated = true; - setAuth({ access_token, isAuthenticated, userInfo, isLoading }); - } else{ - isAuthenticated = false; - setAuth({ access_token, isAuthenticated, userInfo, isLoading }); + // if user is authenticated and tries to access login or signup page, redirect to home + if(NON_AUTHENTICATED_ROUTES.includes(router.pathname)) { + router.push("/"); + } + } else { + setAuth({ access_token, isAuthenticated: false, userInfo, isLoading }); + router.push("/login"); + } + } catch (error) { + router.push("/"); } } - - useEffect(() => { if (auth.isLoading) { checkAuth(); } return () => { auth.isLoading = false; - } + }; }, []); return {props.children}; diff --git a/front/components/security/AuthenticatedOnly.tsx b/front/components/security/AuthenticatedOnly.tsx deleted file mode 100644 index 8612b387..00000000 --- a/front/components/security/AuthenticatedOnly.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from "react"; -import { getRefreshToken, getUserInfo } from "../../services/auth/auth"; -import { Auth, AuthContext } from "./AuthProvider"; - -const AuthenticatedOnly = (props: any) => { - const [auth, setAuth] = React.useState({ access_token: "", isAuthenticated: false, userInfo: {}, isLoading: true }); - - async function checkRefreshToken() { - let data = await getRefreshToken(); - return data.access_token; - } - - async function checkAuth() { - let access_token = await checkRefreshToken(); - let isAuthenticated = false; - let userInfo = {}; - let isLoading = false; - - if (access_token) { - userInfo = await getUserInfo(access_token); - isAuthenticated = true; - setAuth({ access_token, isAuthenticated, userInfo, isLoading }); - } else { - isAuthenticated = false; - setAuth({ access_token, isAuthenticated, userInfo, isLoading }); - } - } - - React.useEffect(() => { - checkAuth(); - }, []); - - return ( -
- {auth.isLoading &&
Loading...
} - {!auth.isLoading && auth.isAuthenticated &&
{props.children}
} - {!auth.isLoading && !auth.isAuthenticated &&
Not Authenticated
} -
- ); -}; - -export default AuthenticatedOnly; diff --git a/front/components/auth/HeaderProfileBox.tsx b/front/components/security/HeaderProfileBox.tsx similarity index 85% rename from front/components/auth/HeaderProfileBox.tsx rename to front/components/security/HeaderProfileBox.tsx index 952c4540..29a1bc0c 100644 --- a/front/components/auth/HeaderProfileBox.tsx +++ b/front/components/security/HeaderProfileBox.tsx @@ -1,8 +1,7 @@ import React from "react"; import styled from "styled-components"; import Link from "next/link"; -import { AuthContext } from "../security/AuthProvider"; -import { getBackendUrl } from "../../services/config"; +import { AuthContext } from "./AuthProvider"; import Avvvatars from "avvvatars-react"; export const HeaderProfileBox = () => { @@ -28,9 +27,9 @@ export const HeaderProfileBox = () => { )} {auth.isAuthenticated && ( -
{auth.userInfo.username}
+
{auth.userInfo.user_object.username}
- +
)} diff --git a/front/components/ui/elements/menu.tsx b/front/components/ui/elements/menu.tsx index 08873fc9..db5e5049 100644 --- a/front/components/ui/elements/menu.tsx +++ b/front/components/ui/elements/menu.tsx @@ -1,6 +1,6 @@ import React from "react"; import styled from "styled-components"; -import { HeaderProfileBox } from "../../auth/HeaderProfileBox"; +import { HeaderProfileBox } from "../../security/HeaderProfileBox"; import learnhouseIcon from "public/learnhouse_icon.png"; import learnhouseLogo from "public/learnhouse_logo.png"; import Link from "next/link"; diff --git a/front/pages/org/[orgslug]/course/[courseid]/element/[elementid]/index.tsx b/front/pages/org/[orgslug]/course/[courseid]/element/[elementid]/index.tsx index cbe3fdd9..1a2a8300 100644 --- a/front/pages/org/[orgslug]/course/[courseid]/element/[elementid]/index.tsx +++ b/front/pages/org/[orgslug]/course/[courseid]/element/[elementid]/index.tsx @@ -30,7 +30,7 @@ function ElementPage() { }, [router.isReady]); const output = useMemo(() => { - if (router.isReady) { + if (router.isReady && !isLoading) { console.log( "el",element.content); let content = Object.keys(element.content).length > 0 ? element.content : { diff --git a/front/pages/org/[orgslug]/course/[courseid]/index.tsx b/front/pages/org/[orgslug]/course/[courseid]/index.tsx index f4d96afc..05c2823d 100644 --- a/front/pages/org/[orgslug]/course/[courseid]/index.tsx +++ b/front/pages/org/[orgslug]/course/[courseid]/index.tsx @@ -6,7 +6,6 @@ import styled from "styled-components"; import Layout from "../../../../../components/ui/Layout"; import { getAPIUrl, getBackendUrl } from "../../../../../services/config"; import { getCourse, getCourseMetadata } from "../../../../../services/courses/courses"; -import { getOrganizationContextInfo } from "../../../../../services/orgs"; const CourseIdPage = () => { const router = useRouter(); @@ -57,7 +56,7 @@ const CourseIdPage = () => { return ( <> - + {" "} diff --git a/front/pages/organizations/index.tsx b/front/pages/organizations/index.tsx index ce2b5a25..9844c06d 100644 --- a/front/pages/organizations/index.tsx +++ b/front/pages/organizations/index.tsx @@ -1,6 +1,5 @@ import Link from "next/link"; import React from "react"; -import AuthenticatedOnly from "../../components/security/AuthenticatedOnly"; import Layout from "../../components/ui/Layout"; import { Title } from "../../components/ui/styles/Title"; import { deleteOrganizationFromBackend, getUserOrganizations } from "../../services/orgs"; @@ -33,7 +32,6 @@ const Organizations = () => { return ( - Your Organizations{" "} <Link href={"/organizations/new"}> @@ -61,7 +59,6 @@ const Organizations = () => { ))} </div> )} - </AuthenticatedOnly> </Layout> ); diff --git a/front/pages/organizations/update.tsx b/front/pages/organizations/update.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/front/services/auth/auth.ts b/front/services/auth/auth.ts index 99e936b1..9a2b0177 100644 --- a/front/services/auth/auth.ts +++ b/front/services/auth/auth.ts @@ -37,7 +37,7 @@ export async function getUserInfo(token: string): Promise<any> { credentials: "include", }; - return fetch(`${getAPIUrl()}users/profile`, requestOptions) + return fetch(`${getAPIUrl()}users/profile_metadata`, requestOptions) .then((result) => result.json()) .catch((error) => console.log("error", error)); } diff --git a/src/routers/users.py b/src/routers/users.py index b6dadc3e..a1f9eded 100644 --- a/src/routers/users.py +++ b/src/routers/users.py @@ -24,6 +24,13 @@ async def api_get_current_user(current_user: User = Depends(get_current_user)): """ return current_user.dict() +@router.get("/profile_metadata") +async def api_get_current_user(current_user: User = Depends(get_current_user)): + """ + Get current user + """ + return await get_profile_metadata(current_user.dict()) + @router.get("/username/{username}") async def api_get_user_by_username(username: str): diff --git a/src/services/users.py b/src/services/users.py index 159afa9b..1831931a 100644 --- a/src/services/users.py +++ b/src/services/users.py @@ -35,6 +35,18 @@ class UserInDB(UserWithPassword): creationDate: str updateDate: str + +class UserProfileMetadata(BaseModel): + user_object: PublicUser + roles = list + +# TODO : terrible, export role classes from one single source of truth +class Role(BaseModel): + name: str + description: str + permissions: object + elements: object + #### Classes #################################################### # TODO : user actions security @@ -55,6 +67,31 @@ async def get_user(username: str): return user +async def get_profile_metadata(user): + await check_database() + users = learnhouseDB["users"] + roles = learnhouseDB["roles"] + + user = users.find_one({"user_id": user['user_id']}) + + if not user: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="User does not exist") + + # get roles + user_roles = roles.find({"linked_users": user['user_id']}) + + user_roles_list = [] + for role in user_roles: + print(role) + user_roles_list.append(Role(**role)) + + return { + "user_object": PublicUser(**user), + "roles": user_roles_list + } + + async def get_user_by_userid(user_id: str): await check_database() users = learnhouseDB["users"]