feat: init install + cleanup code

This commit is contained in:
swve 2023-11-20 22:38:49 +01:00
parent 2485285a06
commit 38288e8a57
28 changed files with 310 additions and 583 deletions

View file

@ -1,33 +1,15 @@
from datetime import datetime
from uuid import uuid4
from fastapi import HTTPException, Request, status
from pydantic import BaseModel
import requests
from fastapi import HTTPException, Request
from sqlalchemy import desc
from sqlmodel import Session, select
from src.db.install import Install
from src.db.organizations import Organization, OrganizationCreate
from src.db.roles import Permission, Rights, Role, RoleTypeEnum
from src.db.user_organizations import UserOrganization
from src.db.users import User, UserCreate, UserRead
from config.config import get_learnhouse_config
from src.security.security import security_hash_password
from src.services.courses.activities.activities import Activity, create_activity
from src.services.orgs.schemas.orgs import Organization, OrganizationInDB
from faker import Faker
from src.services.roles.schemas.roles import Elements, Permission, RoleInDB
from src.services.users.schemas.users import (
PublicUser,
User,
UserInDB,
UserOrganization,
UserRolesInOrganization,
UserWithPassword,
)
class InstallInstance(BaseModel):
install_id: str
created_date: str
updated_date: str
step: int
data: dict
async def isInstallModeEnabled():
@ -42,37 +24,29 @@ async def isInstallModeEnabled():
)
async def create_install_instance(request: Request, data: dict):
installs = request.app.db["installs"]
async def create_install_instance(request: Request, data: dict, db_session: Session):
install = Install.from_orm(data)
# get install_id
install_id = str(f"install_{uuid4()}")
created_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
updated_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
step = 1
# complete install instance
install.install_uuid = str(f"install_{uuid4()}")
install.update_date = str(datetime.now())
install.creation_date = str(datetime.now())
# create install
install = InstallInstance(
install_id=install_id,
created_date=created_date,
updated_date=updated_date,
step=step,
data=data,
)
# insert install instance
db_session.add(install)
# insert install
installs.insert_one(install.dict())
# commit changes
db_session.commit()
# refresh install instance
db_session.refresh(install)
return install
async def get_latest_install_instance(request: Request):
installs = request.app.db["installs"]
# get latest created install instance using find_one
install = await installs.find_one(
sort=[("created_date", -1)], limit=1, projection={"_id": 0}
)
async def get_latest_install_instance(request: Request, db_session: Session):
statement = select(Install).order_by(desc(Install.creation_date)).limit(1)
install = db_session.exec(statement).first()
if install is None:
raise HTTPException(
@ -80,37 +54,31 @@ async def get_latest_install_instance(request: Request):
detail="No install instance found",
)
else:
install = InstallInstance(**install)
return install
return install
async def update_install_instance(request: Request, data: dict, step: int):
installs = request.app.db["installs"]
# get latest created install
install = await installs.find_one(
sort=[("created_date", -1)], limit=1, projection={"_id": 0}
)
async def update_install_instance(
request: Request, data: dict, step: int, db_session: Session
):
statement = select(Install).order_by(desc(Install.creation_date)).limit(1)
install = db_session.exec(statement).first()
if install is None:
return None
else:
# update install
install["data"] = data
install["step"] = step
install["updated_date"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# update install
await installs.update_one(
{"install_id": install["install_id"]}, {"$set": install}
raise HTTPException(
status_code=404,
detail="No install instance found",
)
install = InstallInstance(**install)
install.step = step
install.data = data
return install
# commit changes
db_session.commit()
# refresh install instance
db_session.refresh(install)
return install
############################################################################################################
@ -119,24 +87,34 @@ async def update_install_instance(request: Request, data: dict, step: int):
# Install Default roles
async def install_default_elements(request: Request, data: dict):
roles = request.app.db["roles"]
async def install_default_elements(request: Request, data: dict, db_session: Session):
# remove all default roles
statement = select(Role).where(Role.role_type == RoleTypeEnum.TYPE_GLOBAL)
roles = db_session.exec(statement).all()
# check if default roles ADMIN_ROLE and USER_ROLE already exist
admin_role = await roles.find_one({"role_id": "role_admin"})
user_role = await roles.find_one({"role_id": "role_member"})
for role in roles:
db_session.delete(role)
if admin_role is not None or user_role is not None:
db_session.commit()
# Check if default roles already exist
statement = select(Role).where(Role.role_type == RoleTypeEnum.TYPE_GLOBAL)
roles = db_session.exec(statement).all()
if roles and len(roles) == 3:
raise HTTPException(
status_code=400,
status_code=409,
detail="Default roles already exist",
)
# get default roles
ADMIN_ROLE = RoleInDB(
name="Admin Role",
description="This role grants all permissions to the user",
elements=Elements(
# Create default roles
role_global_admin = Role(
name="Admin",
description="Standard Admin Role",
id=1,
role_type=RoleTypeEnum.TYPE_GLOBAL,
role_uuid="role_global_admin",
rights=Rights(
courses=Permission(
action_create=True,
action_read=True,
@ -149,12 +127,6 @@ async def install_default_elements(request: Request, data: dict):
action_update=True,
action_delete=True,
),
houses=Permission(
action_create=True,
action_read=True,
action_update=True,
action_delete=True,
),
collections=Permission(
action_create=True,
action_read=True,
@ -180,16 +152,65 @@ async def install_default_elements(request: Request, data: dict):
action_delete=True,
),
),
org_id="*",
role_id="role_admin",
created_at=str(datetime.now()),
updated_at=str(datetime.now()),
creation_date=str(datetime.now()),
update_date=str(datetime.now()),
)
USER_ROLE = RoleInDB(
name="Member Role",
description="This role grants read-only permissions to the user",
elements=Elements(
role_global_maintainer = Role(
name="Maintainer",
description="Standard Maintainer Role",
id=2,
role_type=RoleTypeEnum.TYPE_GLOBAL,
role_uuid="role_global_maintainer",
rights=Rights(
courses=Permission(
action_create=True,
action_read=True,
action_update=True,
action_delete=True,
),
users=Permission(
action_create=True,
action_read=True,
action_update=True,
action_delete=True,
),
collections=Permission(
action_create=True,
action_read=True,
action_update=True,
action_delete=True,
),
organizations=Permission(
action_create=True,
action_read=True,
action_update=True,
action_delete=True,
),
coursechapters=Permission(
action_create=True,
action_read=True,
action_update=True,
action_delete=True,
),
activities=Permission(
action_create=True,
action_read=True,
action_update=True,
action_delete=True,
),
),
creation_date=str(datetime.now()),
update_date=str(datetime.now()),
)
role_global_user = Role(
name="User",
description="Standard User Role",
role_type=RoleTypeEnum.TYPE_GLOBAL,
role_uuid="role_global_user",
id=3,
rights=Rights(
courses=Permission(
action_create=False,
action_read=True,
@ -197,13 +218,7 @@ async def install_default_elements(request: Request, data: dict):
action_delete=False,
),
users=Permission(
action_create=False,
action_read=True,
action_update=False,
action_delete=False,
),
houses=Permission(
action_create=False,
action_create=True,
action_read=True,
action_update=False,
action_delete=False,
@ -233,185 +248,122 @@ async def install_default_elements(request: Request, data: dict):
action_delete=False,
),
),
org_id="*",
role_id="role_member",
created_at=str(datetime.now()),
updated_at=str(datetime.now()),
creation_date=str(datetime.now()),
update_date=str(datetime.now()),
)
try:
# insert default roles
await roles.insert_many([USER_ROLE.dict(), ADMIN_ROLE.dict()])
return True
# Serialize rights to JSON
role_global_admin.rights = role_global_admin.rights.dict() # type: ignore
role_global_maintainer.rights = role_global_maintainer.rights.dict() # type: ignore
role_global_user.rights = role_global_user.rights.dict() # type: ignore
except Exception:
raise HTTPException(
status_code=400,
detail="Error while inserting default roles",
)
# Insert roles in DB
db_session.add(role_global_admin)
db_session.add(role_global_maintainer)
db_session.add(role_global_user)
# commit changes
db_session.commit()
# refresh roles
db_session.refresh(role_global_admin)
return True
# Organization creation
async def install_create_organization(
request: Request,
org_object: Organization,
request: Request, org_object: OrganizationCreate, db_session: Session
):
orgs = request.app.db["organizations"]
request.app.db["users"]
org = Organization.from_orm(org_object)
# find if org already exists using name
# Complete the org object
org.org_uuid = f"org_{uuid4()}"
org.creation_date = str(datetime.now())
org.update_date = str(datetime.now())
isOrgAvailable = await orgs.find_one({"slug": org_object.slug.lower()})
db_session.add(org)
db_session.commit()
db_session.refresh(org)
if isOrgAvailable:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Organization slug already exists",
)
# generate org_id with uuid4
org_id = str(f"org_{uuid4()}")
org = OrganizationInDB(org_id=org_id, **org_object.dict())
org_in_db = await orgs.insert_one(org.dict())
if not org_in_db:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Unavailable database",
)
return org.dict()
return org
async def install_create_organization_user(
request: Request, user_object: UserWithPassword, org_slug: str
request: Request, user_object: UserCreate, org_slug: str, db_session: Session
):
users = request.app.db["users"]
user = User.from_orm(user_object)
isUsernameAvailable = await users.find_one({"username": user_object.username})
isEmailAvailable = await users.find_one({"email": user_object.email})
# Complete the user object
user.user_uuid = f"user_{uuid4()}"
user.password = await security_hash_password(user_object.password)
user.email_verified = False
user.creation_date = str(datetime.now())
user.update_date = str(datetime.now())
if isUsernameAvailable:
# Verifications
# Check if Organization exists
statement = select(Organization).where(Organization.slug == org_slug)
org = db_session.exec(statement)
if not org.first():
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Username already exists"
status_code=400,
detail="Organization does not exist",
)
if isEmailAvailable:
# Username
statement = select(User).where(User.username == user.username)
result = db_session.exec(statement)
if result.first():
raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Email already exists"
status_code=400,
detail="Username already exists",
)
# Generate user_id with uuid4
user_id = str(f"user_{uuid4()}")
# Email
statement = select(User).where(User.email == user.email)
result = db_session.exec(statement)
# Set the username & hash the password
user_object.username = user_object.username.lower()
user_object.password = await security_hash_password(user_object.password)
# Get org_id from org_slug
orgs = request.app.db["organizations"]
# Check if the org exists
isOrgExists = await orgs.find_one({"slug": org_slug})
# If the org does not exist, raise an error
if not isOrgExists:
if result.first():
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="You are trying to create a user in an organization that does not exist",
status_code=400,
detail="Email already exists",
)
org_id = isOrgExists["org_id"]
# Exclude unset values
user_data = user.dict(exclude_unset=True)
for key, value in user_data.items():
setattr(user, key, value)
# Create initial orgs list with the org_id passed in
orgs = [UserOrganization(org_id=org_id, org_role="owner")]
# Add user to database
db_session.add(user)
db_session.commit()
db_session.refresh(user)
# Give role
roles = [UserRolesInOrganization(role_id="role_admin", org_id=org_id)]
# Create the user
user = UserInDB(
user_id=user_id,
# get org id
statement = select(Organization).where(Organization.slug == org_slug)
org = db_session.exec(statement)
org = org.first()
org_id = org.id if org else 0
# Link user and organization
user_organization = UserOrganization(
user_id=user.id if user.id else 0,
org_id=org_id or 0,
role_id=1,
creation_date=str(datetime.now()),
update_date=str(datetime.now()),
orgs=orgs,
roles=roles,
**user_object.dict(),
)
# Insert the user into the database
await users.insert_one(user.dict())
db_session.add(user_organization)
db_session.commit()
db_session.refresh(user_organization)
return User(**user.dict())
user = UserRead.from_orm(user)
async def create_sample_data(org_slug: str, username: str, request: Request):
Faker(["en_US"])
fake_multilang = Faker(
["en_US", "de_DE", "ja_JP", "es_ES", "it_IT", "pt_BR", "ar_PS"]
)
users = request.app.db["users"]
orgs = request.app.db["organizations"]
user = await users.find_one({"username": username})
org = await orgs.find_one({"slug": org_slug.lower()})
user_id = user["user_id"]
org_id = org["org_id"]
current_user = PublicUser(**user)
for i in range(0, 5):
# get image in BinaryIO format from unsplash and save it to disk
image = requests.get("https://source.unsplash.com/random/800x600")
with open("thumbnail.jpg", "wb") as f:
f.write(image.content)
# course_id = f"course_{uuid4()}"
# course = CourseInDB(
# name=fake_multilang.unique.sentence(),
# description=fake_multilang.unique.text(),
# mini_description=fake_multilang.unique.text(),
# thumbnail="thumbnail",
# org_id=org_id,
# learnings=[fake_multilang.unique.sentence() for i in range(0, 5)],
# public=True,
# chapters=[],
# course_id=course_id,
# creationDate=str(datetime.now()),
# updateDate=str(datetime.now()),
# authors=[user_id],
# chapters_content=[],
# )
# courses = request.app.db["courses"]
# course = CourseInDB(**course.dict())
# await courses.insert_one(course.dict())
# # create chapters
# for i in range(0, 5):
# coursechapter = CourseChapter(
# name=fake_multilang.unique.sentence(),
# description=fake_multilang.unique.text(),
# activities=[],
# )
# coursechapter = await create_coursechapter(
# request, coursechapter, course_id, current_user
# )
# if coursechapter:
# # create activities
# for i in range(0, 5):
# activity = Activity(
# name=fake_multilang.unique.sentence(),
# type="dynamic",
# content={},
# )
# activity = await create_activity(
# request,
# activity,
# org_id,
# coursechapter["coursechapter_id"],
# current_user,
# )
return user