diff --git a/app.py b/app.py index c890ae26..a09626a9 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,6 @@ import logging from fastapi import FastAPI, Request +import re from src.core.config.config import Settings, get_settings from src.core.events.events import shutdown_app, startup_app from src.main import global_router @@ -23,9 +24,11 @@ app = FastAPI( root_path="/" ) +origin_regex = re.compile(r"^http://[\w.-]+\.localhost:3000$") app.add_middleware( CORSMiddleware, + allow_origin_regex=str(origin_regex.pattern), allow_origins=["http://localhost:3000", "http://localhost:3001"], allow_methods=["*"], allow_credentials=True, diff --git a/docker-compose.yml b/docker-compose.yml index 9373ef5e..148e6b90 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,12 +6,6 @@ services: - "1338:80" volumes: - .:/usr/learnhouse - frontend: - build: ./front - ports: - - "3001:3000" - volumes: - - ./front:/usr/learnhouse/front mongo: image: mongo:5.0 restart: always diff --git a/front/app/_orgs/[orgslug]/course/[courseid]/lecture/[lectureid]/edit/page.tsx b/front/app/_editor/course/[courseid]/lecture/[lectureid]/edit/page.tsx similarity index 78% rename from front/app/_orgs/[orgslug]/course/[courseid]/lecture/[lectureid]/edit/page.tsx rename to front/app/_editor/course/[courseid]/lecture/[lectureid]/edit/page.tsx index a73ce2ca..a10cb3b8 100644 --- a/front/app/_orgs/[orgslug]/course/[courseid]/lecture/[lectureid]/edit/page.tsx +++ b/front/app/_editor/course/[courseid]/lecture/[lectureid]/edit/page.tsx @@ -4,9 +4,9 @@ import { default as React, useEffect, useRef } from "react"; import { useRouter } from "next/navigation"; -import { getLecture } from "../../../../../../../../services/courses/lectures"; -import AuthProvider from "../../../../../../../../components/Security/AuthProvider"; -import EditorWrapper from "../../../../../../../../components/Editor/EditorWrapper"; +import { getLecture } from "@services/courses/lectures"; +import AuthProvider from "@components/Security/AuthProvider"; +import EditorWrapper from "@components/Editor/EditorWrapper"; import useSWR, { mutate } from "swr"; import { getAPIUrl } from "@services/config"; import { swrFetcher } from "@services/utils/requests"; diff --git a/front/app/_editor/main.ts b/front/app/_editor/main.ts new file mode 100644 index 00000000..e5c583e4 --- /dev/null +++ b/front/app/_editor/main.ts @@ -0,0 +1 @@ +export const EDITOR = "main"; diff --git a/front/app/_orgs/[orgslug]/course/[courseid]/lecture/[lectureid]/page.tsx b/front/app/_orgs/[orgslug]/course/[courseid]/lecture/[lectureid]/page.tsx index b9ae1ff8..d66a3ec3 100644 --- a/front/app/_orgs/[orgslug]/course/[courseid]/lecture/[lectureid]/page.tsx +++ b/front/app/_orgs/[orgslug]/course/[courseid]/lecture/[lectureid]/page.tsx @@ -4,7 +4,7 @@ import Link from "next/link"; import React, { useMemo } from "react"; import Layout from "@components/UI/Layout"; import { getLecture } from "@services/courses/lectures"; -import { getAPIUrl, getBackendUrl } from "@services/config"; +import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config"; import Canva from "@components/LectureViews/DynamicCanva/DynamicCanva"; import styled from "styled-components"; import { getCourse } from "@services/courses/courses"; @@ -39,7 +39,7 @@ function LecturePage(params: any) { - + @@ -56,7 +56,7 @@ function LecturePage(params: any) { {chapter.lectures.map((lecture: any) => { return ( <> - + {" "} diff --git a/front/app/_orgs/[orgslug]/course/[courseid]/page.tsx b/front/app/_orgs/[orgslug]/course/[courseid]/page.tsx index 214b064d..c76d2974 100644 --- a/front/app/_orgs/[orgslug]/course/[courseid]/page.tsx +++ b/front/app/_orgs/[orgslug]/course/[courseid]/page.tsx @@ -4,7 +4,7 @@ import { closeActivity, createActivity } from "@services/courses/activity"; import Link from "next/link"; import React from "react"; import styled from "styled-components"; -import { getAPIUrl, getBackendUrl } from "@services/config"; +import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config"; import useSWR, { mutate } from "swr"; import { swrFetcher } from "@services/utils/requests"; @@ -45,7 +45,7 @@ const CourseIdPage = (params: any) => {

Course

{course.course.name}{" "} - + {" "}

@@ -56,7 +56,7 @@ const CourseIdPage = (params: any) => { {chapter.lectures.map((lecture: any) => { return ( <> - + {" "} @@ -97,7 +97,7 @@ const CourseIdPage = (params: any) => { <>

Lecture {lecture.name} - + {" "}

diff --git a/front/app/_orgs/[orgslug]/courses/page.tsx b/front/app/_orgs/[orgslug]/courses/page.tsx index b3da79c3..153e702a 100644 --- a/front/app/_orgs/[orgslug]/courses/page.tsx +++ b/front/app/_orgs/[orgslug]/courses/page.tsx @@ -44,8 +44,8 @@ const CoursesIndexPage = (params: any) => { - - + + diff --git a/front/app/_orgs/[orgslug]/layout.tsx b/front/app/_orgs/[orgslug]/layout.tsx index bf66f8aa..4269ad70 100644 --- a/front/app/_orgs/[orgslug]/layout.tsx +++ b/front/app/_orgs/[orgslug]/layout.tsx @@ -2,7 +2,8 @@ import "@styles/globals.css"; import { Menu } from "@components/UI/Elements/Menu"; import AuthProvider from "@components/Security/AuthProvider"; -export default function RootLayout({ children }: { children: React.ReactNode }) { +export default function RootLayout({ children, params }: { children: React.ReactNode , params:any}) { + return ( <> diff --git a/front/app/_orgs/[orgslug]/page.tsx b/front/app/_orgs/[orgslug]/page.tsx index 5a9611b9..a613b7c8 100644 --- a/front/app/_orgs/[orgslug]/page.tsx +++ b/front/app/_orgs/[orgslug]/page.tsx @@ -1,5 +1,6 @@ "use client"; import { Title } from "@components/UI/Elements/Styles/Title"; +import { getUriWithOrg } from "@services/config"; import Link from "next/link"; import { usePathname } from "next/navigation"; @@ -10,7 +11,7 @@ const OrgHomePage = (params: any) => { return (
Welcome {orgslug} 👋🏻 - +
diff --git a/front/app/login/page.tsx b/front/app/login/page.tsx index b6e11910..19bf4ba7 100644 --- a/front/app/login/page.tsx +++ b/front/app/login/page.tsx @@ -7,8 +7,8 @@ import { Title } from "../../components/UI/Elements/Styles/Title"; import { loginAndGetToken } from "../../services/auth/auth"; const Login = () => { - const [email, setEmail] = React.useState(""); - const [password, setPassword] = React.useState(""); + const [email, setEmail] = React.useState("admin@admin.admin"); + const [password, setPassword] = React.useState("admin"); const router = useRouter(); const handleSubmit = (e: any) => { @@ -39,7 +39,7 @@ const Login = () => { Login
- + diff --git a/front/components/Drags/Lecture.tsx b/front/components/Drags/Lecture.tsx index eb097f4d..513b686a 100644 --- a/front/components/Drags/Lecture.tsx +++ b/front/components/Drags/Lecture.tsx @@ -3,6 +3,7 @@ import React from "react"; import { Draggable } from "react-beautiful-dnd"; import { EyeOpenIcon, Pencil2Icon } from '@radix-ui/react-icons' import styled from "styled-components"; +import { getUriWithOrg } from "@services/config"; function Lecture(props: any) { @@ -12,13 +13,13 @@ function Lecture(props: any) {

{props.lecture.name}

    diff --git a/front/middleware.ts b/front/middleware.ts index c7fffed5..e398e591 100644 --- a/front/middleware.ts +++ b/front/middleware.ts @@ -20,11 +20,6 @@ export default function middleware(req: NextRequest) { // Get hostname of request (e.g. demo.vercel.pub, demo.localhost:3000) const hostname = req.headers.get("host") || "learnhouse.app"; - // Only for demo purposes - remove this if you want to use your root domain as the landing page - if (hostname === "vercel.pub" || hostname === "platforms.vercel.app") { - return NextResponse.redirect("https://demo.vercel.pub"); - } - /* You have to replace ".vercel.pub" with your own domain if you deploy this example under your domain. You can also use wildcard subdomains on .vercel.app links that are associated with your Vercel team slug in this case, our team slug is "platformize", thus *.platformize.vercel.app works. Do note that you'll @@ -33,31 +28,29 @@ export default function middleware(req: NextRequest) { process.env.NODE_ENV === "production" && process.env.VERCEL === "1" ? hostname.replace(`.vercel.pub`, "").replace(`.platformize.vercel.app`, "") : hostname.replace(`.localhost:3000`, ""); - - // if url starts with "/organizations" rewrite to path + + /* Editor route */ + if (url.pathname.match(/^\/course\/[^/]+\/lecture\/[^/]+\/edit$/)) { + url.pathname = `/_editor${url.pathname}`; + console.log("editor route", url.pathname); + + return NextResponse.rewrite(url, { headers: { orgslug: currentHost } }); + } + + /* Organizations route */ if (url.pathname.startsWith("/organizations")) { url.pathname = url.pathname.replace("/organizations", `/organizations${currentHost}`); // remove localhost:3000 from url url.pathname = url.pathname.replace(`localhost:3000`, ""); - console.log(url); + return NextResponse.rewrite(url); } - else if (url.pathname.startsWith("/org")) { - url.pathname = url.pathname.replace("/organizations", `/_orgs/${currentHost}`); - // remove localhost:3000 from url - - url.pathname = `/_orgs/${currentHost}${url.pathname}`; - url.pathname = url.pathname.replace(`localhost:3000/org/`, ""); - console.log(url); - - return NextResponse.rewrite(url); - } + console.log("currentHost", url); // rewrite everything else to `/_sites/[site] dynamic route url.pathname = `/_orgs/${currentHost}${url.pathname}`; - console.log(url); - - return NextResponse.rewrite(url, { headers: { "olgslug": currentHost } }); + + return NextResponse.rewrite(url, { headers: { olgslug: currentHost } }); } diff --git a/front/services/auth/auth.ts b/front/services/auth/auth.ts index 68fa25e9..56e61322 100644 --- a/front/services/auth/auth.ts +++ b/front/services/auth/auth.ts @@ -10,7 +10,10 @@ interface LoginAndGetTokenResponse { export async function loginAndGetToken(username: string, password: string): Promise { // Request Config - const HeadersConfig = new Headers({ "Content-Type": "application/x-www-form-urlencoded" , Origin: "http://localhost:3000" }); + + // get origin + const origin = window.location.origin; + const HeadersConfig = new Headers({ "Content-Type": "application/x-www-form-urlencoded" , Origin: origin }); const urlencoded = new URLSearchParams({ username: username, password: password }); const requestOptions: any = { @@ -28,7 +31,8 @@ export async function loginAndGetToken(username: string, password: string): Prom } export async function getUserInfo(token: string): Promise { - const HeadersConfig = new Headers({ Authorization: `Bearer ${token}`, Origin: "http://localhost:3000" }); + const origin = window.location.origin; + const HeadersConfig = new Headers({ Authorization: `Bearer ${token}`, Origin:origin }); const requestOptions: any = { method: "GET", diff --git a/front/services/config.ts b/front/services/config.ts index dce3e900..caec07fe 100644 --- a/front/services/config.ts +++ b/front/services/config.ts @@ -6,16 +6,13 @@ export const getAPIUrl = () => LEARNHOUSE_API_URL; export const getBackendUrl = () => LEARNHOUSE_BACKEND_URL; export const getUriWithOrg = (orgslug: string, path: string) => { - return `http://localhost:3000/org/${orgslug}${path}`; + return `http://${orgslug}.localhost:3000${path}`; }; -export const getOrgFromUri = (uri: any) => { - // if url contains /org - if (uri.includes("/org/")) { - let org = uri.match(/\/org\/([\w]+)/)[1]; - return org; - } - else { - return ""; - } +export const getOrgFromUri = () => { + const hostname = window.location.hostname; + // get the orgslug from the hostname + const orgslug = hostname.split(".")[0]; + return orgslug; + }; diff --git a/src/dependencies/auth.py b/src/dependencies/auth.py index b4f33a62..92777f4f 100644 --- a/src/dependencies/auth.py +++ b/src/dependencies/auth.py @@ -18,6 +18,8 @@ class Settings(BaseModel): authjwt_token_location = {"cookies"} authjwt_cookie_csrf_protect = False authjwt_access_token_expires = False # (pre-alpha only) # TODO: set to 1 hour + authjwt_cookie_samesite = "none" + authjwt_cookie_secure = True @AuthJWT.load_config # type: ignore