diff --git a/config/config.py b/config/config.py
index e94ae341..afe0a99a 100644
--- a/config/config.py
+++ b/config/config.py
@@ -1,3 +1,4 @@
+from typing import Optional
from pydantic import BaseModel
import os
import yaml
@@ -19,6 +20,7 @@ class DatabaseConfig(BaseModel):
user: str
password: str
database_name: str
+ mongodb_connection_string: Optional[str]
class LearnHouseConfig(BaseModel):
@@ -54,6 +56,8 @@ def get_learnhouse_config() -> LearnHouseConfig:
env_user = os.environ.get('LEARNHOUSE_DB_USER')
env_password = os.environ.get('LEARNHOUSE_DB_PASSWORD')
env_database_name = os.environ.get('LEARNHOUSE_DB_NAME')
+ env_mongodb_connection_string = os.environ.get(
+ 'LEARNHOUSE_MONGODB_CONNECTION_STRING')
# Fill in values with YAML file if they are not provided
site_name = env_site_name or yaml_config.get('site_name')
@@ -80,6 +84,8 @@ def get_learnhouse_config() -> LearnHouseConfig:
'database_config', {}).get('password')
database_name = env_database_name or yaml_config.get(
'database_config', {}).get('database_name')
+ mongodb_connection_string = env_mongodb_connection_string or yaml_config.get(
+ 'database_config', {}).get('mongodb_connection_string')
# Create HostingConfig and DatabaseConfig objects
hosting_config = HostingConfig(
@@ -96,7 +102,8 @@ def get_learnhouse_config() -> LearnHouseConfig:
port=int(db_port),
user=user,
password=password,
- database_name=database_name
+ database_name=database_name,
+ mongodb_connection_string=mongodb_connection_string
)
# Create LearnHouseConfig object
diff --git a/config/config.yaml b/config/config.yaml
index 65532180..d813e5e2 100644
--- a/config/config.yaml
+++ b/config/config.yaml
@@ -20,3 +20,4 @@ database_config:
user: myuser
password: mypassword
database_name: mydatabase
+ mongodb_connection_string: mongodb://learnhouse:learnhouse@mongo:27017/
diff --git a/content/uploads/__init__.py b/content/uploads/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/front/app/_editor/course/[courseid]/activity/[activityid]/edit/page.tsx b/front/app/_editor/course/[courseid]/activity/[activityid]/edit/page.tsx
index 778ec4f0..6539e6c6 100644
--- a/front/app/_editor/course/[courseid]/activity/[activityid]/edit/page.tsx
+++ b/front/app/_editor/course/[courseid]/activity/[activityid]/edit/page.tsx
@@ -9,7 +9,7 @@ import AuthProvider from "@components/Security/AuthProvider";
import EditorWrapper from "@components/Editor/EditorWrapper";
import useSWR, { mutate } from "swr";
import { getAPIUrl } from "@services/config/config";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
function EditActivity(params: any) {
diff --git a/front/app/_orgs/[orgslug]/(withmenu)/collections/new/page.tsx b/front/app/_orgs/[orgslug]/(withmenu)/collections/new/page.tsx
index da1f8355..5a190dec 100644
--- a/front/app/_orgs/[orgslug]/(withmenu)/collections/new/page.tsx
+++ b/front/app/_orgs/[orgslug]/(withmenu)/collections/new/page.tsx
@@ -5,7 +5,7 @@ import { Title } from "@components/UI/Elements/Styles/Title";
import { createCollection } from "@services/courses/collections";
import useSWR from "swr";
import { getAPIUrl } from "@services/config/config";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
import { getOrganizationContextInfo } from "@services/organizations/orgs";
function NewCollection(params : any) {
diff --git a/front/app/_orgs/[orgslug]/(withmenu)/collections/page.tsx b/front/app/_orgs/[orgslug]/(withmenu)/collections/page.tsx
index c74dd467..a6169647 100644
--- a/front/app/_orgs/[orgslug]/(withmenu)/collections/page.tsx
+++ b/front/app/_orgs/[orgslug]/(withmenu)/collections/page.tsx
@@ -5,7 +5,7 @@ import styled from "styled-components";
import { Title } from "@components/UI/Elements/Styles/Title";
import { deleteCollection } from "@services/courses/collections";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
import useSWR, { mutate } from "swr";
function Collections(params: any) {
diff --git a/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/activity/[activityid]/page.tsx b/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/activity/[activityid]/page.tsx
index 480040f2..020c734d 100644
--- a/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/activity/[activityid]/page.tsx
+++ b/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/activity/[activityid]/page.tsx
@@ -10,7 +10,7 @@ import { getCourse } from "@services/courses/courses";
import VideoActivity from "@components/Pages/Activities/Video/Video";
import useSWR, { mutate } from "swr";
import { Check } from "lucide-react";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
import { markActivityAsComplete } from "@services/courses/activity";
function ActivityPage(params: any) {
@@ -19,7 +19,7 @@ function ActivityPage(params: any) {
const orgslug = params.params.orgslug;
const { data: course, error: error_course } = useSWR(`${getAPIUrl()}courses/meta/course_${courseid}`, swrFetcher);
- const { data: activity, error: error_activity } = useSWR(`${getAPIUrl()}trail/org_slug/${orgslug}/trail`, swrFetcher);
+ const { data: activity, error: error_activity } = useSWR(`${getAPIUrl()}activities/activity_${activityid}`, swrFetcher);
async function markActivityAsCompleteFront() {
@@ -31,7 +31,7 @@ function ActivityPage(params: any) {
return (
<>
{error_course &&
Failed to load
}
- {!course || !activity ? (
+ {!course && !activity ? (
Loading...
) : (
@@ -95,9 +95,8 @@ function ActivityPage(params: any) {
)}
- ) : (
- Loading...
- )}
+ ) : ()}
+ {error_activity && Failed to load {error_activity.message}
}
)}
>
diff --git a/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/edit/page.tsx b/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/edit/page.tsx
index 45f0d10f..f2bd7c06 100644
--- a/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/edit/page.tsx
+++ b/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/edit/page.tsx
@@ -15,6 +15,7 @@ import { createActivity, createFileActivity } from "@services/courses/activities
import { getOrganizationContextInfo } from "@services/organizations/orgs";
import Modal from "@components/UI/Modal/Modal";
import AuthProvider from "@components/Security/AuthProvider";
+import { denyAccessToUser } from "@services/utils/react/middlewares/views";
function CourseEdit(params: any) {
@@ -38,9 +39,7 @@ function CourseEdit(params: any) {
const courseChapters = await getCourseChaptersMetadata(courseid);
setData(courseChapters);
} catch (error: any) {
- if (error.status === 401) {
- router.push("/login");
- }
+ denyAccessToUser(error, router)
}
}
diff --git a/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/page.tsx b/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/page.tsx
index 0f2f3b4c..f098e2b6 100644
--- a/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/page.tsx
+++ b/front/app/_orgs/[orgslug]/(withmenu)/course/[courseid]/page.tsx
@@ -1,21 +1,26 @@
"use client";
import { EyeOpenIcon, Pencil2Icon } from "@radix-ui/react-icons";
-import { removeCourse, startCourse } from "@services/courses/activity";
+import { removeCourse, startCourse } from "@services/courses/activity";
import Link from "next/link";
import React from "react";
import styled from "styled-components";
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
import useSWR, { mutate } from "swr";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
+import { useRouter } from "next/navigation";
const CourseIdPage = (params: any) => {
const courseid = params.params.courseid;
const orgslug = params.params.orgslug;
- const { data: course, error: error } = useSWR(`${getAPIUrl()}courses/meta/course_${courseid}`, swrFetcher);
+ const router = useRouter();
+
+ const { data: course, error: error } = useSWR(`${getAPIUrl()}courses/meta/course_${courseid}`,
+ (url: string, body: any) => swrFetcher(url, body, router)
+ );
async function startCourseUI() {
// Create activity
- await startCourse("course_" + courseid, orgslug);
+ await startCourse("course_" + courseid, orgslug);
// Mutate course
mutate(`${getAPIUrl()}courses/meta/course_${courseid}`);
@@ -24,7 +29,7 @@ const CourseIdPage = (params: any) => {
async function quitCourse() {
// Close activity
- let activity = await removeCourse("course_" + courseid, orgslug);
+ let activity = await removeCourse("course_" + courseid, orgslug);
console.log(activity);
// Mutate course
@@ -42,7 +47,7 @@ const CourseIdPage = (params: any) => {
Course
{course.course.name}{" "}
-
+
{" "}
@@ -53,7 +58,7 @@ const CourseIdPage = (params: any) => {
{chapter.activities.map((activity: any) => {
return (
<>
-
+
{" "}
>
@@ -94,7 +99,7 @@ const CourseIdPage = (params: any) => {
<>
Activity {activity.name}
-
+
{" "}
diff --git a/front/app/_orgs/[orgslug]/(withmenu)/courses/page.tsx b/front/app/_orgs/[orgslug]/(withmenu)/courses/page.tsx
index 86706ad1..d7bfa2cd 100644
--- a/front/app/_orgs/[orgslug]/(withmenu)/courses/page.tsx
+++ b/front/app/_orgs/[orgslug]/(withmenu)/courses/page.tsx
@@ -7,7 +7,7 @@ import { Title } from "@components/UI/Elements/Styles/Title";
import { getAPIUrl, getBackendUrl, getSelfHostedOption, getUriWithOrg } from "@services/config/config";
import { deleteCourseFromBackend } from "@services/courses/courses";
import useSWR, { mutate } from "swr";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
import { Edit2, Trash } from "lucide-react";
const CoursesIndexPage = (params: any) => {
diff --git a/front/app/_orgs/[orgslug]/(withmenu)/trail/page.tsx b/front/app/_orgs/[orgslug]/(withmenu)/trail/page.tsx
index 2d86dacb..f965dce1 100644
--- a/front/app/_orgs/[orgslug]/(withmenu)/trail/page.tsx
+++ b/front/app/_orgs/[orgslug]/(withmenu)/trail/page.tsx
@@ -1,6 +1,6 @@
"use client";
import { getAPIUrl, getBackendUrl } from "@services/config/config";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
import React from "react";
import { styled } from "styled-components";
import useSWR from "swr";
diff --git a/front/app/_orgs/[orgslug]/settings/organization/general/page.tsx b/front/app/_orgs/[orgslug]/settings/organization/general/page.tsx
index 4ecd1249..048f4fc2 100644
--- a/front/app/_orgs/[orgslug]/settings/organization/general/page.tsx
+++ b/front/app/_orgs/[orgslug]/settings/organization/general/page.tsx
@@ -1,7 +1,7 @@
"use client";
import React from 'react'
import useSWR, { mutate } from "swr";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
import { getAPIUrl } from '@services/config/config';
import { Field, Form, Formik } from 'formik';
import { updateOrganization } from '@services/settings/org';
diff --git a/front/app/organizations/page.tsx b/front/app/organizations/page.tsx
index ba286b4c..312ec33b 100644
--- a/front/app/organizations/page.tsx
+++ b/front/app/organizations/page.tsx
@@ -4,7 +4,7 @@ import React from "react";
import { Title } from "../../components/UI/Elements/Styles/Title";
import { deleteOrganizationFromBackend } from "@services/organizations/orgs";
import useSWR, { mutate } from "swr";
-import { swrFetcher } from "@services/utils/requests";
+import { swrFetcher } from "@services/utils/ts/requests";
import { getAPIUrl, getUriWithOrg } from "@services/config/config";
import AuthProvider from "@components/Security/AuthProvider";
diff --git a/front/middleware.ts b/front/middleware.ts
index 56fd95cd..baeb1761 100644
--- a/front/middleware.ts
+++ b/front/middleware.ts
@@ -1,4 +1,4 @@
-import { getDefaultOrg, getSelfHostedOption } from "@services/config/config";
+
import { NextRequest, NextResponse } from "next/server";
export const config = {
@@ -15,13 +15,16 @@ export const config = {
],
};
-export default function middleware(req: NextRequest) {
- const url = req.nextUrl;
- const isSelfHosted = getSelfHostedOption();
- const hostname = req.headers.get("host") || "learnhouse.app";
- let currentHost = hostname.replace(".localhost:3000", "");
- if (!isSelfHosted && currentHost === "localhost:3000" && !url.pathname.startsWith("/organizations")) {
+export default function middleware(req: NextRequest) {
+ const LEARNHOUSE_DOMAIN = process.env.NEXT_PUBLIC_LEARNHOUSE_DOMAIN;
+ const url = req.nextUrl;
+ const isSelfHosted = process.env.NEXT_PUBLIC_LEARNHOUSE_SELF_HOSTED === "true" ? true : false
+ const hostname = req.headers.get("host") || "learnhouse.app";
+ const defaultOrg = isSelfHosted ? process.env.NEXT_PUBLIC_LEARNHOUSE_DEFAULT_ORG : null;
+ let currentHost = hostname.replace(`.${LEARNHOUSE_DOMAIN}`, "");
+
+ if (!isSelfHosted && currentHost === LEARNHOUSE_DOMAIN && !url.pathname.startsWith("/organizations")) {
// Redirect to error page if not self-hosted and on localhost
const errorUrl = "/error";
return NextResponse.redirect(errorUrl, { status: 302 });
@@ -42,7 +45,7 @@ export default function middleware(req: NextRequest) {
}
if (isSelfHosted) {
- currentHost = getDefaultOrg() || currentHost;
+ currentHost = defaultOrg || currentHost;
}
url.pathname = `/_orgs/${currentHost}${url.pathname}`;
diff --git a/front/package.json b/front/package.json
index eea65ed2..fe1bceca 100644
--- a/front/package.json
+++ b/front/package.json
@@ -24,7 +24,7 @@
"formik": "^2.2.9",
"framer-motion": "^7.3.6",
"lucide-react": "^0.104.1",
- "next": "^13.2.0",
+ "next": "^13.2.4",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-dom": "^18.2.0",
diff --git a/front/services/blocks/Image/images.ts b/front/services/blocks/Image/images.ts
index bb93582b..0429b6dd 100644
--- a/front/services/blocks/Image/images.ts
+++ b/front/services/blocks/Image/images.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody, RequestBodyForm } from "@services/utils/requests";
+import { RequestBody, RequestBodyForm } from "@services/utils/ts/requests";
export async function uploadNewImageFile(file: any, activity_id: string) {
// Send file thumbnail as form data
diff --git a/front/services/blocks/Pdf/pdf.ts b/front/services/blocks/Pdf/pdf.ts
index 2bff8fbe..fc9b4e5e 100644
--- a/front/services/blocks/Pdf/pdf.ts
+++ b/front/services/blocks/Pdf/pdf.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody, RequestBodyForm } from "@services/utils/requests";
+import { RequestBody, RequestBodyForm } from "@services/utils/ts/requests";
export async function uploadNewPDFFile(file: any, activity_id: string) {
// Send file thumbnail as form data
diff --git a/front/services/blocks/Quiz/quiz.ts b/front/services/blocks/Quiz/quiz.ts
index 706bbf00..0adb85dd 100644
--- a/front/services/blocks/Quiz/quiz.ts
+++ b/front/services/blocks/Quiz/quiz.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody, RequestBodyForm } from "@services/utils/requests";
+import { RequestBody, RequestBodyForm } from "@services/utils/ts/requests";
export async function submitQuizBlock(activity_id: string, data: any) {
diff --git a/front/services/blocks/Video/video.ts b/front/services/blocks/Video/video.ts
index a2c45388..bf7142b4 100644
--- a/front/services/blocks/Video/video.ts
+++ b/front/services/blocks/Video/video.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody, RequestBodyForm } from "@services/utils/requests";
+import { RequestBody, RequestBodyForm } from "@services/utils/ts/requests";
export async function uploadNewVideoFile(file: any, activity_id: string) {
// Send file thumbnail as form data
diff --git a/front/services/config/config.ts b/front/services/config/config.ts
index 8e9a63a6..ed5ee7e4 100644
--- a/front/services/config/config.ts
+++ b/front/services/config/config.ts
@@ -1,5 +1,7 @@
-const LEARNHOUSE_API_URL = "http://localhost:1338/api/";
-const LEARNHOUSE_BACKEND_URL = "http://localhost:1338/";
+const LEARNHOUSE_HTTP_PROTOCOL = process.env.NEXT_PUBLIC_LEARNHOUSE_HTTPS === "true" ? "https://" : "http://";
+const LEARNHOUSE_API_URL = `${process.env.NEXT_PUBLIC_LEARNHOUSE_API_URL}`;
+const LEARNHOUSE_BACKEND_URL = `${process.env.NEXT_PUBLIC_LEARNHOUSE_BACKEND_URL}`;
+export const LEARNHOUSE_DOMAIN = process.env.NEXT_PUBLIC_LEARNHOUSE_DOMAIN;
export const getAPIUrl = () => LEARNHOUSE_API_URL;
export const getBackendUrl = () => LEARNHOUSE_BACKEND_URL;
@@ -7,11 +9,10 @@ export const getSelfHostedOption = () => (process.env.NEXT_PUBLIC_LEARNHOUSE_SEL
export const getUriWithOrg = (orgslug: string, path: string) => {
const selfHosted = getSelfHostedOption();
-
if (selfHosted) {
- return `http://localhost:3000${path}`;
+ return `${LEARNHOUSE_DOMAIN}${path}`;
}
- return `http://${orgslug}.localhost:3000${path}`;
+ return `${LEARNHOUSE_HTTP_PROTOCOL}${orgslug}.${LEARNHOUSE_DOMAIN}${path}`;
};
export const getOrgFromUri = () => {
@@ -21,8 +22,8 @@ export const getOrgFromUri = () => {
} else {
if (typeof window !== "undefined") {
const hostname = window.location.hostname;
-
- return hostname.replace(".localhost", "");
+
+ return hostname.replace(`.${LEARNHOUSE_DOMAIN}`, "");
}
}
};
diff --git a/front/services/courses/activities.ts b/front/services/courses/activities.ts
index 9ee811d6..fa378281 100644
--- a/front/services/courses/activities.ts
+++ b/front/services/courses/activities.ts
@@ -1,19 +1,14 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody, RequestBodyForm } from "@services/utils/requests";
+import { RequestBody, RequestBodyForm } from "@services/utils/ts/requests";
export async function createActivity(data: any, chapter_id: any, org_id: any) {
data.content = {};
// remove chapter_id from data
delete data.chapterId;
-
- const result: any = await fetch(`${getAPIUrl()}activities/?coursechapter_id=${chapter_id}&org_id=${org_id}`, RequestBody("POST", data))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- console.log("result", result);
-
- return result;
+ const result = await fetch(`${getAPIUrl()}activities/?coursechapter_id=${chapter_id}&org_id=${org_id}`, RequestBody("POST", data));
+ const res = await result.json();
+ return res;
}
export async function createFileActivity(file: File, type: string, data: any, chapter_id: any) {
@@ -29,27 +24,19 @@ export async function createFileActivity(file: File, type: string, data: any, ch
endpoint = `${getAPIUrl()}activities/video`;
}
- const result: any = await fetch(endpoint, RequestBodyForm("POST", formData))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- console.log("result", result);
-
- return result;
+ const result: any = await fetch(endpoint, RequestBodyForm("POST", formData));
+ const res = await result.json();
+ return res;
}
export async function getActivity(activity_id: any) {
- const result: any = await fetch(`${getAPIUrl()}activities/${activity_id}`, RequestBody("GET", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- return result;
+ const result = await fetch(`${getAPIUrl()}activities/${activity_id}`, RequestBody("GET", null));
+ const res = await result.json();
+ return res;
}
export async function updateActivity(data: any, activity_id: any) {
- const result: any = await fetch(`${getAPIUrl()}activities/${activity_id}`, RequestBody("PUT", data))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- return result;
+ const result = await fetch(`${getAPIUrl()}activities/${activity_id}`, RequestBody("PUT", data));
+ const res = await result.json();
+ return res;
}
diff --git a/front/services/courses/activity.ts b/front/services/courses/activity.ts
index d2fcda94..aec4ec45 100644
--- a/front/services/courses/activity.ts
+++ b/front/services/courses/activity.ts
@@ -1,4 +1,4 @@
-import { RequestBody } from "@services/utils/requests";
+import { RequestBody, errorHandling } from "@services/utils/ts/requests";
import { getAPIUrl } from "@services/config/config";
/*
@@ -8,21 +8,18 @@ import { getAPIUrl } from "@services/config/config";
export async function startCourse(course_id: string, org_slug: string) {
const result: any = await fetch(`${getAPIUrl()}trail/org_slug/${org_slug}/add_course/${course_id}`, RequestBody("POST", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
- return result;
+ const res = await errorHandling(result);
+ return res;
}
export async function removeCourse(course_id: string, org_slug: string) {
const result: any = await fetch(`${getAPIUrl()}trail/org_slug/${org_slug}/remove_course/${course_id}`, RequestBody("POST", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
- return result;
+ const res = await errorHandling(result);
+ return res;
}
export async function markActivityAsComplete(org_slug: string, course_id: string, activity_id: string) {
const result: any = await fetch(`${getAPIUrl()}trail/org_slug/${org_slug}/add_activity/course_id/${course_id}/activity_id/${activity_id}`, RequestBody("POST", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
- return result;
+ const res = await errorHandling(result);
+ return res;
}
diff --git a/front/services/courses/chapters.ts b/front/services/courses/chapters.ts
index 8bdc85e2..ddf2c521 100644
--- a/front/services/courses/chapters.ts
+++ b/front/services/courses/chapters.ts
@@ -1,6 +1,5 @@
-import { initialData } from "../../components/Pages/CourseEdit/Draggables/data";
import { getAPIUrl } from "@services/config/config";
-import { RequestBody } from "@services/utils/requests";
+import { RequestBody, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
@@ -9,38 +8,26 @@ import { RequestBody } from "@services/utils/requests";
//TODO : depreciate this function
export async function getCourseChaptersMetadata(course_id: any) {
- const response = await fetch(`${getAPIUrl()}chapters/meta/course_${course_id}`, RequestBody("GET", null));
-
- if (!response.ok) {
- const error: any = new Error(`Error ${response.status}: ${response.statusText}`, {});
- error.status = response.status;
- throw error;
- }
-
- const data = await response.json();
- return data;
+ const result = await fetch(`${getAPIUrl()}chapters/meta/course_${course_id}`, RequestBody("GET", null));
+ const res = await errorHandling(result);
+ return res;
}
export async function updateChaptersMetadata(course_id: any, data: any) {
- const result: any = await fetch(`${getAPIUrl()}chapters/meta/course_${course_id}`, RequestBody("PUT", data))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- return result;
+ const result: any = await fetch(`${getAPIUrl()}chapters/meta/course_${course_id}`, RequestBody("PUT", data));
+ const res = await errorHandling(result);
+ return res;
}
export async function createChapter(data: any, course_id: any) {
- const result: any = await fetch(`${getAPIUrl()}chapters/?course_id=course_${course_id}`, RequestBody("POST", data))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result: any = await fetch(`${getAPIUrl()}chapters/?course_id=course_${course_id}`, RequestBody("POST", data));
+ const res = await errorHandling(result);
- return result;
+ return res;
}
export async function deleteChapter(coursechapter_id: any) {
- const result: any = await fetch(`${getAPIUrl()}chapters/${coursechapter_id}`, RequestBody("DELETE", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- return result;
+ const result: any = await fetch(`${getAPIUrl()}chapters/${coursechapter_id}`, RequestBody("DELETE", null));
+ const res = await errorHandling(result);
+ return res;
}
diff --git a/front/services/courses/collections.ts b/front/services/courses/collections.ts
index 2f213f0b..09ca1610 100644
--- a/front/services/courses/collections.ts
+++ b/front/services/courses/collections.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "../config/config";
-import { RequestBody } from "../utils/requests";
+import { RequestBody, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
@@ -7,14 +7,14 @@ import { RequestBody } from "../utils/requests";
*/
export async function deleteCollection(collection_id: any) {
- return fetch(`${getAPIUrl()}collections/${collection_id}`, RequestBody("DELETE", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result: any = await fetch(`${getAPIUrl()}collections/${collection_id}`, RequestBody("DELETE", null));
+ const res = await errorHandling(result);
+ return res;
}
// Create a new collection
export async function createCollection(collection: any) {
- return fetch(`${getAPIUrl()}collections/`, RequestBody("POST", collection))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result: any = await fetch(`${getAPIUrl()}collections/`, RequestBody("POST", collection));
+ const res = await errorHandling(result);
+ return res;
}
diff --git a/front/services/courses/courses.ts b/front/services/courses/courses.ts
index d7307e70..13486429 100644
--- a/front/services/courses/courses.ts
+++ b/front/services/courses/courses.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody, RequestBodyForm } from "@services/utils/requests";
+import { RequestBody, RequestBodyForm, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
@@ -7,23 +7,18 @@ import { RequestBody, RequestBodyForm } from "@services/utils/requests";
*/
export async function getOrgCourses(org_id: number) {
-
-
- return fetch(`${getAPIUrl()}courses/${org_id}/page/1/limit/10`, RequestBody("GET", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result: any = await fetch(`${getAPIUrl()}courses/${org_id}/page/1/limit/10`, RequestBody("GET", null));
+ const res = await errorHandling(result);
+ return res;
}
export async function getCourse(course_id: string) {
- // todo : add course id to url
- return fetch(`${getAPIUrl()}courses/${course_id}`, RequestBody("GET", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result: any = await fetch(`${getAPIUrl()}courses/${course_id}`, RequestBody("GET", null));
+ const res = await errorHandling(result);
+ return res;
}
-
export async function createNewCourse(org_id: string, course_body: any, thumbnail: any) {
-
// Send file thumbnail as form data
const formData = new FormData();
formData.append("thumbnail", thumbnail);
@@ -32,16 +27,13 @@ export async function createNewCourse(org_id: string, course_body: any, thumbnai
formData.append("mini_description", "course_body.mini_description");
formData.append("public", "true");
-
- return fetch(`${getAPIUrl()}courses/?org_id=${org_id}`, RequestBodyForm("POST", formData))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result = await fetch(`${getAPIUrl()}courses/?org_id=${org_id}`, RequestBodyForm("POST", formData));
+ const res = await errorHandling(result);
+ return res;
}
export async function deleteCourseFromBackend(course_id: any) {
-
-
- return fetch(`${getAPIUrl()}courses/${course_id}`, RequestBody("DELETE", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result: any = await fetch(`${getAPIUrl()}courses/${course_id}`, RequestBody("DELETE", null));
+ const res = await errorHandling(result);
+ return res;
}
diff --git a/front/services/organizations/orgs.ts b/front/services/organizations/orgs.ts
index ddd6fde4..2718df70 100644
--- a/front/services/organizations/orgs.ts
+++ b/front/services/organizations/orgs.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody } from "../utils/requests";
+import { RequestBody, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
@@ -7,19 +7,19 @@ import { RequestBody } from "../utils/requests";
*/
export async function createNewOrganization(body: any) {
- return fetch(`${getAPIUrl()}orgs/`, RequestBody("POST", body))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result = await fetch(`${getAPIUrl()}orgs/`, RequestBody("POST", body));
+ const res = await errorHandling(result);
+ return res;
}
export async function deleteOrganizationFromBackend(org_id: any) {
- return fetch(`${getAPIUrl()}orgs/${org_id}`, RequestBody("DELETE", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result = await fetch(`${getAPIUrl()}orgs/${org_id}`, RequestBody("DELETE", null));
+ const res = await errorHandling(result);
+ return res;
}
export async function getOrganizationContextInfo(org_slug: any) {
- return fetch(`${getAPIUrl()}orgs/slug/${org_slug}`, RequestBody("GET", null))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const result = await fetch(`${getAPIUrl()}orgs/slug/${org_slug}`, RequestBody("GET", null));
+ const res = await errorHandling(result);
+ return res;
}
diff --git a/front/services/settings/org.ts b/front/services/settings/org.ts
index 10842ca2..1f4a0fd8 100644
--- a/front/services/settings/org.ts
+++ b/front/services/settings/org.ts
@@ -1,15 +1,13 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody } from "@services/utils/requests";
+import { RequestBody, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
GET requests are called from the frontend using SWR (https://swr.vercel.app/)
*/
-export async function updateOrganization(org_id : string, data: any) {
- const result: any = await fetch(`${getAPIUrl()}orgs/` + org_id, RequestBody("PUT", data))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- return result;
+export async function updateOrganization(org_id: string, data: any) {
+ const result: any = await fetch(`${getAPIUrl()}orgs/` + org_id, RequestBody("PUT", data));
+ const res = await errorHandling(result);
+ return res;
}
diff --git a/front/services/settings/password.ts b/front/services/settings/password.ts
index b4c13bb3..a93483f3 100644
--- a/front/services/settings/password.ts
+++ b/front/services/settings/password.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody } from "@services/utils/requests";
+import { RequestBody, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
@@ -8,8 +8,6 @@ import { RequestBody } from "@services/utils/requests";
export async function updatePassword(user_id : string, data: any) {
const result: any = await fetch(`${getAPIUrl()}users/password/user_id/` + user_id, RequestBody("PUT", data))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- return result;
+ const res = await errorHandling(result);
+ return res;
}
diff --git a/front/services/settings/profile.ts b/front/services/settings/profile.ts
index bb1a048a..06f0667e 100644
--- a/front/services/settings/profile.ts
+++ b/front/services/settings/profile.ts
@@ -1,5 +1,5 @@
import { getAPIUrl } from "@services/config/config";
-import { RequestBody } from "@services/utils/requests";
+import { RequestBody, errorHandling } from "@services/utils/ts/requests";
/*
This file includes only POST, PUT, DELETE requests
@@ -8,8 +8,6 @@ import { RequestBody } from "@services/utils/requests";
export async function updateProfile(data: any) {
const result: any = await fetch(`${getAPIUrl()}users/user_id/` + data.user_id, RequestBody("PUT", data))
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
-
- return result;
+ const res = await errorHandling(result);
+ return res;
}
diff --git a/front/services/utils/react/middlewares/views.ts b/front/services/utils/react/middlewares/views.ts
new file mode 100644
index 00000000..6ab82348
--- /dev/null
+++ b/front/services/utils/react/middlewares/views.ts
@@ -0,0 +1,14 @@
+import { AppRouterInstance } from "next/dist/shared/lib/app-router-context";
+import { NextRouter } from "next/router";
+
+export const denyAccessToUser = (error : any, router: AppRouterInstance) => {
+ if (error.status === 401) {
+ router.push("/login");
+ }
+
+ if (error.status === 403) {
+ router.push("/login");
+ // TODO : add a message to the user to tell him he is not allowed to access this page, route to /error
+ }
+
+}
\ No newline at end of file
diff --git a/front/services/utils/requests.ts b/front/services/utils/ts/requests.ts
similarity index 61%
rename from front/services/utils/requests.ts
rename to front/services/utils/ts/requests.ts
index 3f4e6466..802f92ec 100644
--- a/front/services/utils/requests.ts
+++ b/front/services/utils/ts/requests.ts
@@ -1,3 +1,6 @@
+import { AppRouterInstance } from "next/dist/shared/lib/app-router-context";
+import { denyAccessToUser } from "../react/middlewares/views";
+
export const RequestBody = (method: string, data: any) => {
let HeadersConfig = new Headers({ "Content-Type": "application/json" });
let options: any = {
@@ -24,7 +27,7 @@ export const RequestBodyForm = (method: string, data: any) => {
return options;
};
-export const swrFetcher = async (url: string, body: any) => {
+export const swrFetcher = async (url: string, body: any, router?: AppRouterInstance) => {
// Create the request options
let HeadersConfig = new Headers({ "Content-Type": "application/json" });
let options: any = {
@@ -39,15 +42,26 @@ export const swrFetcher = async (url: string, body: any) => {
options.body = JSON.stringify(body);
}
- // Fetch the data
- const res = await fetch(url, options);
+ try {
+ // Fetch the data
+ const request = await fetch(url, options);
+ let res = errorHandling(request);
- // If the response is not in the 200 range, throw an error
- if (!res.ok) {
- const error = new Error("An error occurred while fetching the data.");
+ // Return the data
+ return res;
+ } catch (error: any) {
+ if (router) {
+ denyAccessToUser(error, router);
+ }
throw error;
}
+};
- // Return the data
+export const errorHandling = (res: any) => {
+ if (!res.ok) {
+ const error: any = new Error(`Error ${res.status}: ${res.statusText}`, {});
+ error.status = res.status;
+ throw error;
+ }
return res.json();
};
diff --git a/src/core/events/database.py b/src/core/events/database.py
index 56913242..174575a6 100644
--- a/src/core/events/database.py
+++ b/src/core/events/database.py
@@ -2,17 +2,20 @@ import logging
from fastapi import FastAPI
import motor.motor_asyncio
-async def connect_to_db(app: FastAPI) :
+
+async def connect_to_db(app: FastAPI):
logging.info("Connecting to database...")
try:
- app.mongodb_client = motor.motor_asyncio.AsyncIOMotorClient("mongodb://learnhouse:learnhouse@mongo:27017/") # type: ignore
- app.db = app.mongodb_client["learnhouse"] # type: ignore
+ app.mongodb_client = motor.motor_asyncio.AsyncIOMotorClient( # type: ignore
+ app.learnhouse_config.database_config.mongodb_connection_string) # type: ignore
+ app.db = app.mongodb_client["learnhouse"] # type: ignore
logging.info("Connected to database!")
except Exception as e:
logging.error("Failed to connect to database!")
logging.error(e)
+
async def close_database(app: FastAPI):
- app.mongodb_client.close() # type: ignore
+ app.mongodb_client.close() # type: ignore
logging.info("LearnHouse has been shut down.")
- return app
\ No newline at end of file
+ return app
diff --git a/src/core/events/events.py b/src/core/events/events.py
index 27dd830b..c7afb00f 100644
--- a/src/core/events/events.py
+++ b/src/core/events/events.py
@@ -1,11 +1,16 @@
from typing import Callable
from fastapi import FastAPI
+from config.config import LearnHouseConfig, get_learnhouse_config
from src.core.events.database import close_database, connect_to_db
from src.core.events.logs import create_logs_dir
def startup_app(app: FastAPI) -> Callable:
async def start_app() -> None:
+ # Get LearnHouse Config
+ learnhouse_config: LearnHouseConfig = get_learnhouse_config()
+ app.learnhouse_config = learnhouse_config # type: ignore
+
# Connect to database
await connect_to_db(app)
diff --git a/src/services/courses/courses.py b/src/services/courses/courses.py
index d8dee31a..55b12d67 100644
--- a/src/services/courses/courses.py
+++ b/src/services/courses/courses.py
@@ -288,7 +288,7 @@ async def verify_rights(request: Request, course_id: str, current_user: PublicUs
course = await courses.find_one({"course_id": course_id})
- if current_user.user_id == "anonymous" and course["public"] == True:
+ if current_user.user_id == "anonymous" and course["public"] == True and action == "read":
return True
if not course:
diff --git a/src/services/mocks/initial.py b/src/services/mocks/initial.py
index a4e206ca..ea443c1d 100644
--- a/src/services/mocks/initial.py
+++ b/src/services/mocks/initial.py
@@ -1,3 +1,4 @@
+import os
import requests
from datetime import datetime
from fileinput import filename
@@ -183,7 +184,13 @@ async def create_initial_data(request: Request):
name_in_disk = f"test_mock{course_id}.jpeg"
image = requests.get(
- "https://source.unsplash.com/random/800x600")
+ "https://source.unsplash.com/random/800x600/?img=1")
+
+ # check if folder exists and create it if not
+ if not os.path.exists(f"content/uploads/img"):
+
+ os.makedirs(f"content/uploads/img")
+
with open(f"content/uploads/img/{name_in_disk}", "wb") as f:
f.write(image.content)