mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
Merge pull request #64 from learnhouse/feat/init-self-hosted
feat: use config files and init self hosting options
This commit is contained in:
commit
ecf4e4d6d9
37 changed files with 251 additions and 288 deletions
23
app.py
23
app.py
|
|
@ -1,7 +1,8 @@
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
import re
|
import re
|
||||||
from src.core.config.config import Settings, get_settings
|
from config.config import LearnHouseConfig, get_learnhouse_config
|
||||||
from src.core.events.events import shutdown_app, startup_app
|
from src.core.events.events import shutdown_app, startup_app
|
||||||
from src.main import global_router
|
from src.main import global_router
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
@ -16,10 +17,13 @@ from fastapi_jwt_auth.exceptions import AuthJWTException
|
||||||
# (c) LearnHouse 2022
|
# (c) LearnHouse 2022
|
||||||
########################
|
########################
|
||||||
|
|
||||||
|
# Get LearnHouse Config
|
||||||
|
learnhouse_config: LearnHouseConfig = get_learnhouse_config()
|
||||||
|
|
||||||
# Global Config
|
# Global Config
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="LearnHouse",
|
title=learnhouse_config.site_name,
|
||||||
description="LearnHouse is a new open-source platform tailored for learning experiences.",
|
description=learnhouse_config.site_description,
|
||||||
version="0.1.0",
|
version="0.1.0",
|
||||||
root_path="/"
|
root_path="/"
|
||||||
)
|
)
|
||||||
|
|
@ -45,7 +49,7 @@ app.add_event_handler("shutdown", shutdown_app(app))
|
||||||
|
|
||||||
|
|
||||||
# JWT Exception Handler
|
# JWT Exception Handler
|
||||||
@app.exception_handler(AuthJWTException)
|
@ app.exception_handler(AuthJWTException)
|
||||||
def authjwt_exception_handler(request: Request, exc: AuthJWTException):
|
def authjwt_exception_handler(request: Request, exc: AuthJWTException):
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=exc.status_code, # type: ignore
|
status_code=exc.status_code, # type: ignore
|
||||||
|
|
@ -59,10 +63,19 @@ app.include_router(global_router)
|
||||||
# General Routes
|
# General Routes
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@ app.get("/")
|
||||||
async def root():
|
async def root():
|
||||||
return {"Message": "Welcome to LearnHouse ✨"}
|
return {"Message": "Welcome to LearnHouse ✨"}
|
||||||
|
|
||||||
|
# Get config
|
||||||
|
|
||||||
|
|
||||||
|
@ app.get("/config")
|
||||||
|
async def config():
|
||||||
|
logging.info("Getting config")
|
||||||
|
config = get_learnhouse_config()
|
||||||
|
return config.dict()
|
||||||
|
|
||||||
|
|
||||||
# @app.get("/initial_data")
|
# @app.get("/initial_data")
|
||||||
# async def initial_data(request: Request):
|
# async def initial_data(request: Request):
|
||||||
|
|
|
||||||
111
config/config.py
111
config/config.py
|
|
@ -0,0 +1,111 @@
|
||||||
|
from pydantic import BaseModel
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
class HostingConfig(BaseModel):
|
||||||
|
domain: str
|
||||||
|
port: int
|
||||||
|
ssl: bool
|
||||||
|
use_default_org: bool
|
||||||
|
allowed_origins: list
|
||||||
|
allowed_regexp: str
|
||||||
|
self_hosted: bool
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseConfig(BaseModel):
|
||||||
|
host: str
|
||||||
|
port: int
|
||||||
|
user: str
|
||||||
|
password: str
|
||||||
|
database_name: str
|
||||||
|
|
||||||
|
|
||||||
|
class LearnHouseConfig(BaseModel):
|
||||||
|
site_name: str
|
||||||
|
site_description: str
|
||||||
|
contact_email: str
|
||||||
|
hosting_config: HostingConfig
|
||||||
|
database_config: DatabaseConfig
|
||||||
|
|
||||||
|
|
||||||
|
def get_learnhouse_config() -> LearnHouseConfig:
|
||||||
|
|
||||||
|
# Get the YAML file
|
||||||
|
yaml_path = os.path.join(os.path.dirname(__file__), 'config.yaml')
|
||||||
|
|
||||||
|
# Load the YAML file
|
||||||
|
with open(yaml_path, 'r') as f:
|
||||||
|
yaml_config = yaml.safe_load(f)
|
||||||
|
|
||||||
|
# Check if environment variables are defined
|
||||||
|
env_site_name = os.environ.get('LEARNHOUSE_SITE_NAME')
|
||||||
|
env_site_description = os.environ.get('LEARNHOUSE_SITE_DESCRIPTION')
|
||||||
|
env_contact_email = os.environ.get('LEARNHOUSE_CONTACT_EMAIL')
|
||||||
|
env_domain = os.environ.get('LEARNHOUSE_DOMAIN')
|
||||||
|
env_port = os.environ.get('LEARNHOUSE_PORT')
|
||||||
|
env_ssl = os.environ.get('LEARNHOUSE_SSL')
|
||||||
|
env_use_default_org = os.environ.get('LEARNHOUSE_USE_DEFAULT_ORG')
|
||||||
|
env_allowed_origins = os.environ.get('LEARNHOUSE_ALLOWED_ORIGINS')
|
||||||
|
env_allowed_regexp = os.environ.get('LEARNHOUSE_ALLOWED_REGEXP')
|
||||||
|
env_self_hosted = os.environ.get('LEARNHOUSE_SELF_HOSTED')
|
||||||
|
env_host = os.environ.get('LEARNHOUSE_DB_HOST')
|
||||||
|
env_db_port = os.environ.get('LEARNHOUSE_DB_PORT')
|
||||||
|
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')
|
||||||
|
|
||||||
|
# Fill in values with YAML file if they are not provided
|
||||||
|
site_name = env_site_name or yaml_config.get('site_name')
|
||||||
|
site_description = env_site_description or yaml_config.get(
|
||||||
|
'site_description')
|
||||||
|
contact_email = env_contact_email or yaml_config.get('contact_email')
|
||||||
|
|
||||||
|
domain = env_domain or yaml_config.get('hosting_config', {}).get('domain')
|
||||||
|
port = env_port or yaml_config.get('hosting_config', {}).get('port')
|
||||||
|
ssl = env_ssl or yaml_config.get('hosting_config', {}).get('ssl')
|
||||||
|
use_default_org = env_use_default_org or yaml_config.get(
|
||||||
|
'hosting_config', {}).get('use_default_org')
|
||||||
|
allowed_origins = env_allowed_origins or yaml_config.get(
|
||||||
|
'hosting_config', {}).get('allowed_origins')
|
||||||
|
allowed_regexp = env_allowed_regexp or yaml_config.get(
|
||||||
|
'hosting_config', {}).get('allowed_regexp')
|
||||||
|
self_hosted = env_self_hosted or yaml_config.get(
|
||||||
|
'hosting_config', {}).get('self_hosted')
|
||||||
|
|
||||||
|
host = env_host or yaml_config.get('database_config', {}).get('host')
|
||||||
|
db_port = env_db_port or yaml_config.get('database_config', {}).get('port')
|
||||||
|
user = env_user or yaml_config.get('database_config', {}).get('user')
|
||||||
|
password = env_password or yaml_config.get(
|
||||||
|
'database_config', {}).get('password')
|
||||||
|
database_name = env_database_name or yaml_config.get(
|
||||||
|
'database_config', {}).get('database_name')
|
||||||
|
|
||||||
|
# Create HostingConfig and DatabaseConfig objects
|
||||||
|
hosting_config = HostingConfig(
|
||||||
|
domain=domain,
|
||||||
|
port=int(port),
|
||||||
|
ssl=bool(ssl),
|
||||||
|
use_default_org=bool(use_default_org),
|
||||||
|
allowed_origins=list(allowed_origins),
|
||||||
|
allowed_regexp=allowed_regexp,
|
||||||
|
self_hosted=bool(self_hosted)
|
||||||
|
)
|
||||||
|
database_config = DatabaseConfig(
|
||||||
|
host=host,
|
||||||
|
port=int(db_port),
|
||||||
|
user=user,
|
||||||
|
password=password,
|
||||||
|
database_name=database_name
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create LearnHouseConfig object
|
||||||
|
config = LearnHouseConfig(
|
||||||
|
site_name=site_name,
|
||||||
|
site_description=site_description,
|
||||||
|
contact_email=contact_email,
|
||||||
|
hosting_config=hosting_config,
|
||||||
|
database_config=database_config
|
||||||
|
)
|
||||||
|
|
||||||
|
return config
|
||||||
22
config/config.yaml
Normal file
22
config/config.yaml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
site_name: LearnHouse
|
||||||
|
site_description: LearnHouse is an open-source platform tailored for learning experiences.
|
||||||
|
contact_email: hi@learnhouse.app
|
||||||
|
|
||||||
|
hosting_config:
|
||||||
|
domain: learnhouse.app
|
||||||
|
port: 443
|
||||||
|
ssl: true
|
||||||
|
use_default_org: false
|
||||||
|
default_org: learnhouse
|
||||||
|
allowed_origins:
|
||||||
|
- https://learnhouse.app
|
||||||
|
- https://learnhouse.io
|
||||||
|
allowed_regexp: "^https://(.*\\.)?learnhouse\\.app$"
|
||||||
|
self_hosted: false
|
||||||
|
|
||||||
|
database_config:
|
||||||
|
host: db.mongo
|
||||||
|
port: 5432
|
||||||
|
user: myuser
|
||||||
|
password: mypassword
|
||||||
|
database_name: mydatabase
|
||||||
|
|
@ -4,7 +4,7 @@ import { useRouter } from "next/navigation";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Title } from "@components/UI/Elements/Styles/Title";
|
import { Title } from "@components/UI/Elements/Styles/Title";
|
||||||
import { getAPIUrl, getBackendUrl, getUriWithOrg } from "@services/config/config";
|
import { getAPIUrl, getBackendUrl, getSelfHostedOption, getUriWithOrg } from "@services/config/config";
|
||||||
import { deleteCourseFromBackend } from "@services/courses/courses";
|
import { deleteCourseFromBackend } from "@services/courses/courses";
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
import { swrFetcher } from "@services/utils/requests";
|
import { swrFetcher } from "@services/utils/requests";
|
||||||
|
|
@ -25,7 +25,7 @@ const CoursesIndexPage = (params: any) => {
|
||||||
function removeCoursePrefix(course_id: string) {
|
function removeCoursePrefix(course_id: string) {
|
||||||
return course_id.replace("course_", "");
|
return course_id.replace("course_", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title>
|
<Title>
|
||||||
|
|
@ -44,8 +44,8 @@ const CoursesIndexPage = (params: any) => {
|
||||||
<button style={{ backgroundColor: "red", border: "none" }} onClick={() => deleteCourses(course.course_id)}>
|
<button style={{ backgroundColor: "red", border: "none" }} onClick={() => deleteCourses(course.course_id)}>
|
||||||
Delete <Trash size={10}></Trash>
|
Delete <Trash size={10}></Trash>
|
||||||
</button>
|
</button>
|
||||||
<Link href={getUriWithOrg(orgslug,"") + "/course/" + removeCoursePrefix(course.course_id)}>
|
<Link href={getUriWithOrg(orgslug, "/course/" + removeCoursePrefix(course.course_id))}>
|
||||||
<Link href={getUriWithOrg(orgslug,"") + "/course/" + removeCoursePrefix(course.course_id) + "/edit"}>
|
<Link href={getUriWithOrg(orgslug, "/course/" + removeCoursePrefix(course.course_id) + "/edit")}>
|
||||||
<button>
|
<button>
|
||||||
Edit <Edit2 size={10}></Edit2>
|
Edit <Edit2 size={10}></Edit2>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { getDefaultOrg, getSelfHostedOption } from "@services/config/config";
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
|
|
@ -16,41 +17,34 @@ export const config = {
|
||||||
|
|
||||||
export default function middleware(req: NextRequest) {
|
export default function middleware(req: NextRequest) {
|
||||||
const url = req.nextUrl;
|
const url = req.nextUrl;
|
||||||
|
const isSelfHosted = getSelfHostedOption();
|
||||||
// Get hostname of request (e.g. demo.vercel.pub, demo.localhost:3000)
|
|
||||||
const hostname = req.headers.get("host") || "learnhouse.app";
|
const hostname = req.headers.get("host") || "learnhouse.app";
|
||||||
|
let currentHost = hostname.replace(".localhost:3000", "");
|
||||||
|
|
||||||
/* You have to replace ".vercel.pub" with your own domain if you deploy this example under your domain.
|
if (!isSelfHosted && currentHost === "localhost:3000" && !url.pathname.startsWith("/organizations")) {
|
||||||
You can also use wildcard subdomains on .vercel.app links that are associated with your Vercel team slug
|
// Redirect to error page if not self-hosted and on localhost
|
||||||
in this case, our team slug is "platformize", thus *.platformize.vercel.app works. Do note that you'll
|
const errorUrl = "/error";
|
||||||
still need to add "*.platformize.vercel.app" as a wildcard domain on your Vercel dashboard. */
|
return NextResponse.redirect(errorUrl, { status: 302 });
|
||||||
let currentHost =
|
}
|
||||||
process.env.NODE_ENV === "production" && process.env.VERCEL === "1"
|
|
||||||
? hostname.replace(`.vercel.pub`, "").replace(`.platformize.vercel.app`, "")
|
|
||||||
: hostname.replace(`.localhost:3000`, "");
|
|
||||||
|
|
||||||
/* Editor route */
|
|
||||||
if (url.pathname.match(/^\/course\/[^/]+\/activity\/[^/]+\/edit$/)) {
|
if (url.pathname.match(/^\/course\/[^/]+\/activity\/[^/]+\/edit$/)) {
|
||||||
url.pathname = `/_editor${url.pathname}`;
|
url.pathname = `/_editor${url.pathname}`;
|
||||||
console.log("editor route", url.pathname);
|
|
||||||
|
|
||||||
return NextResponse.rewrite(url, { headers: { orgslug: currentHost } });
|
return NextResponse.rewrite(url, { headers: { orgslug: currentHost } });
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Organizations route */
|
|
||||||
if (url.pathname.startsWith("/organizations")) {
|
if (url.pathname.startsWith("/organizations")) {
|
||||||
url.pathname = url.pathname.replace("/organizations", `/organizations${currentHost}`);
|
if (!isSelfHosted) {
|
||||||
// remove localhost:3000 from url
|
currentHost = "";
|
||||||
url.pathname = url.pathname.replace(`localhost:3000`, "");
|
}
|
||||||
|
url.pathname = url.pathname.replace("/organizations", `/organizations${currentHost}`).replace("localhost:3000", "");
|
||||||
|
|
||||||
return NextResponse.rewrite(url);
|
return NextResponse.rewrite(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("currentHost", url);
|
if (isSelfHosted) {
|
||||||
|
currentHost = getDefaultOrg() || currentHost;
|
||||||
|
}
|
||||||
|
|
||||||
// rewrite everything else to `/_sites/[site] dynamic route
|
|
||||||
url.pathname = `/_orgs/${currentHost}${url.pathname}`;
|
url.pathname = `/_orgs/${currentHost}${url.pathname}`;
|
||||||
|
return NextResponse.rewrite(url, { headers: { orgslug: currentHost } });
|
||||||
return NextResponse.rewrite(url, { headers: { olgslug: currentHost } });
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,33 @@ const LEARNHOUSE_API_URL = "http://localhost:1338/api/";
|
||||||
const LEARNHOUSE_BACKEND_URL = "http://localhost:1338/";
|
const LEARNHOUSE_BACKEND_URL = "http://localhost:1338/";
|
||||||
|
|
||||||
export const getAPIUrl = () => LEARNHOUSE_API_URL;
|
export const getAPIUrl = () => LEARNHOUSE_API_URL;
|
||||||
|
|
||||||
export const getBackendUrl = () => LEARNHOUSE_BACKEND_URL;
|
export const getBackendUrl = () => LEARNHOUSE_BACKEND_URL;
|
||||||
|
export const getSelfHostedOption = () => (process.env.NEXT_PUBLIC_LEARNHOUSE_SELF_HOSTED === "true" ? true : false);
|
||||||
|
|
||||||
export const getUriWithOrg = (orgslug: string, path: string) => {
|
export const getUriWithOrg = (orgslug: string, path: string) => {
|
||||||
|
const selfHosted = getSelfHostedOption();
|
||||||
|
|
||||||
|
if (selfHosted) {
|
||||||
|
return `http://localhost:3000${path}`;
|
||||||
|
}
|
||||||
return `http://${orgslug}.localhost:3000${path}`;
|
return `http://${orgslug}.localhost:3000${path}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getOrgFromUri = () => {
|
export const getOrgFromUri = () => {
|
||||||
const hostname = window.location.hostname;
|
const selfHosted = getSelfHostedOption();
|
||||||
// get the orgslug from the hostname
|
if (selfHosted) {
|
||||||
const orgslug = hostname.split(".")[0];
|
getDefaultOrg();
|
||||||
return orgslug;
|
} else {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
const hostname = window.location.hostname;
|
||||||
|
return hostname.replace(".localhost:3000", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getDefaultOrg = () => {
|
||||||
|
const selfHosted = getSelfHostedOption();
|
||||||
|
if (selfHosted) {
|
||||||
|
return process.env.NEXT_PUBLIC_LEARNHOUSE_DEFAULT_ORG;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
"@editor/*": ["components/Editor/*"]
|
"@editor/*": ["components/Editor/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx","**/**/*.tsx", ".next/types/**/*.ts"],
|
||||||
|
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,5 @@ python-jose
|
||||||
passlib
|
passlib
|
||||||
fastapi-jwt-auth
|
fastapi-jwt-auth
|
||||||
faker
|
faker
|
||||||
requests
|
requests
|
||||||
|
pyyaml
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
from fastapi import FastAPI
|
|
||||||
|
|
||||||
class Settings(FastAPI):
|
|
||||||
title="LearnHousse",
|
|
||||||
description="LearnHouse is a new open-source platform tailored for learning experiences.",
|
|
||||||
version="0.1.0",
|
|
||||||
root_path="/"
|
|
||||||
docs_url="/docs"
|
|
||||||
|
|
||||||
async def get_settings() -> Settings:
|
|
||||||
return Settings()
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from src.core.events.database import close_database, connect_to_db
|
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:
|
def startup_app(app: FastAPI) -> Callable:
|
||||||
|
|
@ -8,6 +9,9 @@ def startup_app(app: FastAPI) -> Callable:
|
||||||
# Connect to database
|
# Connect to database
|
||||||
await connect_to_db(app)
|
await connect_to_db(app)
|
||||||
|
|
||||||
|
# Create logs directory
|
||||||
|
await create_logs_dir()
|
||||||
|
|
||||||
return start_app
|
return start_app
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
24
src/core/events/logs.py
Normal file
24
src/core/events/logs.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
async def create_logs_dir():
|
||||||
|
if not os.path.exists("logs"):
|
||||||
|
os.mkdir("logs")
|
||||||
|
|
||||||
|
# Initiate logging
|
||||||
|
async def init_logging():
|
||||||
|
await create_logs_dir()
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||||
|
datefmt="%d-%b-%y %H:%M:%S",
|
||||||
|
handlers=[
|
||||||
|
logging.FileHandler("logs/learnhouse.log"),
|
||||||
|
logging.StreamHandler()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.info("Logging initiated")
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from src.routers import activity, blocks, users, auth, houses, orgs, roles
|
from src.routers import activity, blocks, users, auth, orgs, roles
|
||||||
from src.routers.courses import chapters, collections, courses,activities
|
from src.routers.courses import chapters, collections, courses,activities
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -9,7 +9,6 @@ global_router = APIRouter(prefix="/api")
|
||||||
# API Routes
|
# API Routes
|
||||||
global_router.include_router(users.router, prefix="/users", tags=["users"])
|
global_router.include_router(users.router, prefix="/users", tags=["users"])
|
||||||
global_router.include_router(auth.router, prefix="/auth", tags=["auth"])
|
global_router.include_router(auth.router, prefix="/auth", tags=["auth"])
|
||||||
global_router.include_router(houses.router, prefix="/houses", tags=["houses"])
|
|
||||||
global_router.include_router(orgs.router, prefix="/orgs", tags=["orgs"])
|
global_router.include_router(orgs.router, prefix="/orgs", tags=["orgs"])
|
||||||
global_router.include_router(roles.router, prefix="/roles", tags=["roles"])
|
global_router.include_router(roles.router, prefix="/roles", tags=["roles"])
|
||||||
global_router.include_router(blocks.router, prefix="/blocks", tags=["blocks"])
|
global_router.include_router(blocks.router, prefix="/blocks", tags=["blocks"])
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
from src.dependencies.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
from src.services.activity import Activity, add_activity_to_activity, close_activity, create_activity, get_user_activities, get_user_activities_orgslug
|
from src.services.activity import Activity, add_activity_to_activity, close_activity, create_activity, get_user_activities, get_user_activities_orgslug
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from urllib.request import Request
|
from urllib.request import Request
|
||||||
from fastapi import Depends, APIRouter, HTTPException, status, Request
|
from fastapi import Depends, APIRouter, HTTPException, status, Request
|
||||||
from fastapi.security import OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordRequestForm
|
||||||
from src.dependencies.auth import *
|
from src.security.auth import *
|
||||||
from src.services.users.users import *
|
from src.services.users.users import *
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from fastapi import APIRouter, Depends, UploadFile, Form, Request
|
from fastapi import APIRouter, Depends, UploadFile, Form, Request
|
||||||
from src.dependencies.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
from fastapi import HTTPException, status, UploadFile
|
from fastapi import HTTPException, status, UploadFile
|
||||||
from src.services.blocks.block_types.imageBlock.images import create_image_block, get_image_block
|
from src.services.blocks.block_types.imageBlock.images import create_image_block, get_image_block
|
||||||
from src.services.blocks.block_types.videoBlock.videoBlock import create_video_block, get_video_block
|
from src.services.blocks.block_types.videoBlock.videoBlock import create_video_block, get_video_block
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from fastapi import APIRouter, Depends, UploadFile, Form, Request
|
from fastapi import APIRouter, Depends, UploadFile, Form, Request
|
||||||
from src.services.courses.activities.activities import *
|
from src.services.courses.activities.activities import *
|
||||||
from src.dependencies.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
from src.services.courses.activities.video import create_video_activity
|
from src.services.courses.activities.video import create_video_activity
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, Request, UploadFile, Form
|
||||||
|
|
||||||
from src.services.courses.chapters import CourseChapter, CourseChapterMetaData, create_coursechapter, delete_coursechapter, get_coursechapter, get_coursechapters, get_coursechapters_meta, update_coursechapter, update_coursechapters_meta
|
from src.services.courses.chapters import CourseChapter, CourseChapterMetaData, create_coursechapter, delete_coursechapter, get_coursechapter, get_coursechapters, get_coursechapters_meta, update_coursechapter, update_coursechapters_meta
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.dependencies.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
from src.dependencies.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
from src.services.users.users import PublicUser, User
|
from src.services.users.users import PublicUser, User
|
||||||
from src.services.courses.collections import Collection, create_collection, get_collection, get_collections, update_collection, delete_collection
|
from src.services.courses.collections import Collection, create_collection, get_collection, get_collections, update_collection, delete_collection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from fastapi import APIRouter, Depends, UploadFile, Form, Request
|
from fastapi import APIRouter, Depends, UploadFile, Form, Request
|
||||||
from src.dependencies.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
|
|
||||||
from src.services.courses.courses import Course, create_course, get_course, get_course_meta, get_courses, get_courses_orgslug, update_course, delete_course, update_course_thumbnail
|
from src.services.courses.courses import Course, create_course, get_course, get_course_meta, get_courses, get_courses_orgslug, update_course, delete_course, update_course_thumbnail
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
from fastapi import APIRouter, Depends, Request
|
|
||||||
from src.dependencies.auth import get_current_user
|
|
||||||
|
|
||||||
from src.services.houses import House, HouseInDB, create_house, get_house, get_houses, update_house, delete_house
|
|
||||||
from src.services.users.users import PublicUser, User
|
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter()
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/")
|
|
||||||
async def api_create_house(request: Request,house_object: House, current_user: PublicUser = Depends(get_current_user)):
|
|
||||||
"""
|
|
||||||
Create new house
|
|
||||||
"""
|
|
||||||
return await create_house(request, house_object, current_user)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{house_id}")
|
|
||||||
async def api_get_house(request: Request,house_id: str, current_user: PublicUser = Depends(get_current_user)):
|
|
||||||
"""
|
|
||||||
Get single House by house_id
|
|
||||||
"""
|
|
||||||
return await get_house(request, house_id, current_user=current_user)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/page/{page}/limit/{limit}")
|
|
||||||
async def api_get_house_by(request: Request,page: int, limit: int):
|
|
||||||
"""
|
|
||||||
Get houses by page and limit
|
|
||||||
"""
|
|
||||||
return await get_houses(request, page, limit)
|
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{house_id}")
|
|
||||||
async def api_update_house(request: Request,house_object: House, house_id: str, current_user: PublicUser = Depends(get_current_user)):
|
|
||||||
"""
|
|
||||||
Update House by house_id
|
|
||||||
"""
|
|
||||||
return await update_house(request, house_object, house_id, current_user)
|
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{house_id}")
|
|
||||||
async def api_delete_house(request: Request,house_id: str, current_user: PublicUser = Depends(get_current_user)):
|
|
||||||
"""
|
|
||||||
Delete House by ID
|
|
||||||
"""
|
|
||||||
|
|
||||||
return await delete_house(request, house_id, current_user)
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
from src.dependencies.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
from src.services.orgs import Organization, create_org, delete_org, get_organization, get_organization_by_slug, get_orgs_by_user, update_org
|
from src.services.orgs import Organization, create_org, delete_org, get_organization, get_organization_by_slug, get_orgs_by_user, update_org
|
||||||
from src.services.users.users import PublicUser, User
|
from src.services.users.users import PublicUser, User
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
from src.dependencies.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
from src.services.roles.schemas.roles import Role
|
from src.services.roles.schemas.roles import Role
|
||||||
from src.services.roles.roles import create_role, delete_role, read_role, update_role
|
from src.services.roles.roles import create_role, delete_role, read_role, update_role
|
||||||
from src.services.users.schemas.users import PublicUser, User
|
from src.services.users.schemas.users import PublicUser, User
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from fastapi import Depends, FastAPI, APIRouter
|
from fastapi import Depends, FastAPI, APIRouter
|
||||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.dependencies.auth import *
|
from src.security.auth import *
|
||||||
from src.services.users.schemas.users import PasswordChangeForm, PublicUser, User, UserWithPassword
|
from src.services.users.schemas.users import PasswordChangeForm, PublicUser, User, UserWithPassword
|
||||||
from src.services.users.users import create_user, delete_user, get_profile_metadata, get_user_by_userid, read_user, update_user, update_user_password
|
from src.services.users.users import create_user, delete_user, get_profile_metadata, get_user_by_userid, read_user, update_user, update_user_password
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from jose import JWTError, jwt
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from src.services.users.users import *
|
from src.services.users.users import *
|
||||||
from fastapi import Cookie, FastAPI
|
from fastapi import Cookie, FastAPI
|
||||||
from src.services.security import *
|
from src.security.security import *
|
||||||
from fastapi_jwt_auth import AuthJWT
|
from fastapi_jwt_auth import AuthJWT
|
||||||
from fastapi_jwt_auth.exceptions import AuthJWTException
|
from fastapi_jwt_auth.exceptions import AuthJWTException
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.services.security import verify_user_rights_with_roles
|
from src.security.security import verify_user_rights_with_roles
|
||||||
from src.services.users.schemas.users import PublicUser, User
|
from src.services.users.schemas.users import PublicUser, User
|
||||||
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
|
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.services.security import verify_user_rights_with_roles
|
from src.security.security import verify_user_rights_with_roles
|
||||||
from src.services.courses.activities.uploads.videos import upload_video
|
from src.services.courses.activities.uploads.videos import upload_video
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.services.courses.activities.activities import ActivityInDB
|
from src.services.courses.activities.activities import ActivityInDB
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.services.courses.courses import Course, CourseInDB
|
from src.services.courses.courses import Course, CourseInDB
|
||||||
from src.services.courses.activities.activities import Activity, ActivityInDB
|
from src.services.courses.activities.activities import Activity, ActivityInDB
|
||||||
from src.services.security import verify_user_rights_with_roles
|
from src.security.security import verify_user_rights_with_roles
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from fastapi import HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
|
from fastapi import HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from typing import List
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.services.users.users import PublicUser, User
|
from src.services.users.users import PublicUser, User
|
||||||
from src.services.security import *
|
from src.security.security import *
|
||||||
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks
|
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from pydantic import BaseModel
|
||||||
from src.services.courses.activities.activities import ActivityInDB
|
from src.services.courses.activities.activities import ActivityInDB
|
||||||
from src.services.courses.thumbnails import upload_thumbnail
|
from src.services.courses.thumbnails import upload_thumbnail
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.services.security import *
|
from src.security.security import *
|
||||||
from fastapi import HTTPException, status, UploadFile
|
from fastapi import HTTPException, status, UploadFile
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
||||||
import json
|
|
||||||
from typing import List
|
|
||||||
from uuid import uuid4
|
|
||||||
from pydantic import BaseModel
|
|
||||||
from src.services.users.users import PublicUser, User
|
|
||||||
from src.services.security import *
|
|
||||||
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
#### Classes ####################################################
|
|
||||||
|
|
||||||
|
|
||||||
class House(BaseModel):
|
|
||||||
name: str
|
|
||||||
photo: str
|
|
||||||
description: str
|
|
||||||
email: str
|
|
||||||
org: str
|
|
||||||
|
|
||||||
|
|
||||||
class HouseInDB(House):
|
|
||||||
house_id: str
|
|
||||||
owners: List[str]
|
|
||||||
admins: List[str]
|
|
||||||
|
|
||||||
#### Classes ####################################################
|
|
||||||
|
|
||||||
# TODO : Add house photo upload and delete
|
|
||||||
|
|
||||||
async def get_house(request: Request, house_id: str, current_user: PublicUser):
|
|
||||||
houses = request.app.db["houses"]
|
|
||||||
|
|
||||||
house = houses.find_one({"house_id": house_id})
|
|
||||||
|
|
||||||
# verify house rights
|
|
||||||
await verify_house_rights(request,house_id, current_user, "read")
|
|
||||||
|
|
||||||
if not house:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="House does not exist")
|
|
||||||
|
|
||||||
house = House(**house)
|
|
||||||
return house
|
|
||||||
|
|
||||||
|
|
||||||
async def create_house(request: Request,house_object: House, current_user: PublicUser):
|
|
||||||
houses = request.app.db["houses"]
|
|
||||||
|
|
||||||
# find if house already exists using name
|
|
||||||
isHouseAvailable = houses.find_one({"name": house_object.name})
|
|
||||||
|
|
||||||
if isHouseAvailable:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="House name already exists")
|
|
||||||
|
|
||||||
# generate house_id with uuid4
|
|
||||||
house_id = str(f"house_{uuid4()}")
|
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(request, "create", current_user.user_id, house_id)
|
|
||||||
|
|
||||||
if not hasRoleRights:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
|
|
||||||
|
|
||||||
house = HouseInDB(house_id=house_id, owners=[
|
|
||||||
current_user.user_id], admins=[
|
|
||||||
current_user.user_id], **house_object.dict())
|
|
||||||
|
|
||||||
house_in_db = houses.insert_one(house.dict())
|
|
||||||
|
|
||||||
if not house_in_db:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
|
|
||||||
|
|
||||||
return house.dict()
|
|
||||||
|
|
||||||
|
|
||||||
async def update_house(request: Request,house_object: House, house_id: str, current_user: PublicUser):
|
|
||||||
|
|
||||||
# verify house rights
|
|
||||||
await verify_house_rights(request,house_id, current_user, "update")
|
|
||||||
|
|
||||||
houses = request.app.db["houses"]
|
|
||||||
|
|
||||||
house = houses.find_one({"house_id": house_id})
|
|
||||||
|
|
||||||
if house:
|
|
||||||
# get owner value from house object database
|
|
||||||
owners = house["owners"]
|
|
||||||
admins = house["admins"]
|
|
||||||
|
|
||||||
updated_house = HouseInDB(
|
|
||||||
house_id=house_id, owners=owners, admins=admins, **house_object.dict())
|
|
||||||
|
|
||||||
houses.update_one({"house_id": house_id}, {"$set": updated_house.dict()})
|
|
||||||
|
|
||||||
return HouseInDB(**updated_house.dict())
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="House does not exist")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def delete_house(request: Request,house_id: str, current_user: PublicUser):
|
|
||||||
|
|
||||||
# verify house rights
|
|
||||||
await verify_house_rights(request,house_id, current_user, "delete")
|
|
||||||
|
|
||||||
houses = request.app.db["houses"]
|
|
||||||
|
|
||||||
house = houses.find_one({"house_id": house_id})
|
|
||||||
|
|
||||||
if not house:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="House does not exist")
|
|
||||||
|
|
||||||
isDeleted = houses.delete_one({"house_id": house_id})
|
|
||||||
|
|
||||||
if isDeleted:
|
|
||||||
return {"detail": "House deleted"}
|
|
||||||
else:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
|
|
||||||
|
|
||||||
|
|
||||||
async def get_houses(request: Request,page: int = 1, limit: int = 10):
|
|
||||||
houses = request.app.db["houses"]
|
|
||||||
# TODO : Get only houses that user is admin/has roles of
|
|
||||||
# get all houses from database
|
|
||||||
all_houses = houses.find().sort("name", 1).skip(10 * (page - 1)).limit(limit)
|
|
||||||
|
|
||||||
return [json.loads(json.dumps(house, default=str)) for house in await all_houses.to_list(length=limit)]
|
|
||||||
|
|
||||||
|
|
||||||
#### Security ####################################################
|
|
||||||
|
|
||||||
async def verify_house_rights(request: Request,house_id: str, current_user: PublicUser, action: str):
|
|
||||||
houses = request.app.db["houses"]
|
|
||||||
|
|
||||||
house = houses.find_one({"house_id": house_id})
|
|
||||||
|
|
||||||
if not house:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="House does not exist")
|
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(request,action, current_user.user_id, house_id)
|
|
||||||
isOwner = current_user.user_id in house["owners"]
|
|
||||||
|
|
||||||
if not hasRoleRights and not isOwner:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN, detail="Roles/Ownership : Insufficient rights to perform this action")
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
#### Security ####################################################
|
|
||||||
|
|
@ -4,7 +4,7 @@ from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.services.users.schemas.users import UserOrganization
|
from src.services.users.schemas.users import UserOrganization
|
||||||
from src.services.users.users import PublicUser, User
|
from src.services.users.users import PublicUser, User
|
||||||
from src.services.security import *
|
from src.security.security import *
|
||||||
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks
|
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
@ -16,12 +16,11 @@ class Organization(BaseModel):
|
||||||
description: str
|
description: str
|
||||||
email: str
|
email: str
|
||||||
slug: str
|
slug: str
|
||||||
|
default: bool
|
||||||
|
|
||||||
|
|
||||||
class OrganizationInDB(Organization):
|
class OrganizationInDB(Organization):
|
||||||
org_id: str
|
org_id: str
|
||||||
owners: List[str]
|
|
||||||
admins: List[str]
|
|
||||||
|
|
||||||
|
|
||||||
class PublicOrganization(Organization):
|
class PublicOrganization(Organization):
|
||||||
|
|
@ -75,15 +74,13 @@ async def create_org(request: Request, org_object: Organization, current_user: P
|
||||||
# generate org_id with uuid4
|
# generate org_id with uuid4
|
||||||
org_id = str(f"org_{uuid4()}")
|
org_id = str(f"org_{uuid4()}")
|
||||||
|
|
||||||
org = OrganizationInDB(org_id=org_id, owners=[
|
org = OrganizationInDB(org_id=org_id, **org_object.dict())
|
||||||
current_user.user_id], admins=[
|
|
||||||
current_user.user_id], **org_object.dict())
|
|
||||||
|
|
||||||
org_in_db = await orgs.insert_one(org.dict())
|
org_in_db = await orgs.insert_one(org.dict())
|
||||||
|
|
||||||
user_organization: UserOrganization = UserOrganization(
|
user_organization: UserOrganization = UserOrganization(
|
||||||
org_id=org_id, org_role="owner")
|
org_id=org_id, org_role="owner")
|
||||||
|
|
||||||
# add org to user
|
# add org to user
|
||||||
await user.update_one({"user_id": current_user.user_id}, {
|
await user.update_one({"user_id": current_user.user_id}, {
|
||||||
"$addToSet": {"orgs": user_organization.dict()}})
|
"$addToSet": {"orgs": user_organization.dict()}})
|
||||||
|
|
@ -113,7 +110,7 @@ async def update_org(request: Request, org_object: Organization, org_id: str, cu
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist")
|
||||||
|
|
||||||
updated_org = OrganizationInDB(
|
updated_org = OrganizationInDB(
|
||||||
org_id=org_id, owners=owners, admins=admins, **org_object.dict())
|
org_id=org_id, **org_object.dict())
|
||||||
|
|
||||||
await orgs.update_one({"org_id": org_id}, {"$set": updated_org.dict()})
|
await orgs.update_one({"org_id": org_id}, {"$set": updated_org.dict()})
|
||||||
|
|
||||||
|
|
@ -149,10 +146,10 @@ async def get_orgs_by_user(request: Request, user_id: str, page: int = 1, limit:
|
||||||
orgs = request.app.db["organizations"]
|
orgs = request.app.db["organizations"]
|
||||||
user = request.app.db["users"]
|
user = request.app.db["users"]
|
||||||
|
|
||||||
# get user orgs
|
# get user orgs
|
||||||
user_orgs = await user.find_one({"user_id": user_id})
|
user_orgs = await user.find_one({"user_id": user_id})
|
||||||
|
|
||||||
org_ids : list[UserOrganization] = []
|
org_ids: list[UserOrganization] = []
|
||||||
|
|
||||||
for org in user_orgs["orgs"]:
|
for org in user_orgs["orgs"]:
|
||||||
if org["org_role"] == "owner" or org["org_role"] == "editor" or org["org_role"] == "member":
|
if org["org_role"] == "owner" or org["org_role"] == "editor" or org["org_role"] == "member":
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@ from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.services.roles.schemas.roles import Role, RoleInDB
|
from src.services.roles.schemas.roles import Role, RoleInDB
|
||||||
from src.services.users.schemas.users import PublicUser, User
|
from src.services.users.schemas.users import PublicUser, User
|
||||||
from src.services.security import *
|
from src.security.security import *
|
||||||
from src.services.houses import House
|
|
||||||
from fastapi import HTTPException, status, Request
|
from fastapi import HTTPException, status, Request
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from typing import Literal
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from fastapi import HTTPException, Request, status
|
from fastapi import HTTPException, Request, status
|
||||||
from src.services.roles.schemas.roles import Role
|
from src.services.roles.schemas.roles import Role
|
||||||
from src.services.security import security_hash_password, security_verify_password
|
from src.security.security import security_hash_password, security_verify_password
|
||||||
from src.services.users.schemas.users import PasswordChangeForm, PublicUser, User, UserOrganization, UserWithPassword, UserInDB
|
from src.services.users.schemas.users import PasswordChangeForm, PublicUser, User, UserOrganization, UserWithPassword, UserInDB
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue