feat: init new config model version

This commit is contained in:
swve 2024-08-09 20:54:41 +02:00
parent b7dc77a0e6
commit 6485b6e1bb
6 changed files with 225 additions and 117 deletions

View file

@ -0,0 +1,69 @@
def migrate_v0_to_v1(v0_config):
v1_config = {
"config_version": "1.0",
"general": {
"enabled": v0_config["GeneralConfig"]["active"],
"color": v0_config["GeneralConfig"]["color"],
"watermark": True, # Default value as it's not present in v0
},
"features": {
"courses": {
"enabled": True,
"limit": (
v0_config["GeneralConfig"]["limits"]["max_users"]
if v0_config["GeneralConfig"]["limits"]["limits_enabled"]
else 5
),
},
"members": {
"enabled": True,
"signup_mode": (
"open"
if v0_config["GeneralConfig"]["users"]["signup_mechanism"] == "open"
else "inviteOnly"
),
"admin_limit": 5,
"limit": (
v0_config["GeneralConfig"]["limits"]["max_users"]
if v0_config["GeneralConfig"]["limits"]["limits_enabled"]
else 10
),
},
"usergroups": {
"enabled": True,
"limit": (
v0_config["GeneralConfig"]["limits"]["max_staff"]
if v0_config["GeneralConfig"]["limits"]["limits_enabled"]
else 10
),
},
"storage": {
"enabled": True,
"limit": (
v0_config["GeneralConfig"]["limits"]["max_storage"]
if v0_config["GeneralConfig"]["limits"]["limits_enabled"]
else 10
),
},
"ai": {
"enabled": v0_config["AIConfig"]["enabled"],
"limit": (
v0_config["AIConfig"]["limits"]["max_asks"]
if v0_config["AIConfig"]["limits"]["limits_enabled"]
else 10
),
"model": v0_config["AIConfig"]["ai_model"],
},
"assignments": {"enabled": True, "limit": 10},
"payments": {"enabled": False, "stripe_key": ""},
"discussions": {"enabled": False, "limit": 10},
"analytics": {"enabled": False, "limit": 10},
"collaboration": {
"enabled": v0_config["GeneralConfig"]["collaboration"],
"limit": 10,
},
"api": {"enabled": False, "limit": 10},
},
}
return v1_config

View file

@ -4,51 +4,91 @@ from sqlalchemy import JSON, BigInteger, Column, ForeignKey
from sqlmodel import Field, SQLModel from sqlmodel import Field, SQLModel
# AI # Features
class AILimitsSettings(BaseModel): class CourseOrgConfig(BaseModel):
limits_enabled: bool = False
max_asks: int = 0
class AIEnabledFeatures(BaseModel):
editor: bool = False
activity_ask: bool = False
course_ask: bool = False
global_ai_ask: bool = False
class AIConfig(BaseModel):
enabled: bool = True enabled: bool = True
limits: AILimitsSettings = AILimitsSettings() limit: int = 10
embeddings: Literal["text-embedding-ada-002"] = "text-embedding-ada-002"
ai_model: Literal["gpt-3.5-turbo", "gpt-4-1106-preview"] = "gpt-3.5-turbo"
features: AIEnabledFeatures = AIEnabledFeatures()
class OrgUserConfig(BaseModel): class MemberOrgConfig(BaseModel):
signup_mechanism: Literal["open", "inviteOnly"] = "open" enabled: bool = True
signup_mode: Literal["open", "inviteOnly"] = "open"
admin_limit: int = 1
limit: int = 10
# Limits class UserGroupOrgConfig(BaseModel):
class LimitSettings(BaseModel): enabled: bool = True
limits_enabled: bool = False limit: int = 10
max_users: int = 0
max_storage: int = 0
max_staff: int = 0 class StorageOrgConfig(BaseModel):
enabled: bool = True
limit: int = 10
class AIOrgConfig(BaseModel):
enabled: bool = True
limit: int = 10
model: str = "gpt-4o-mini"
class AssignmentOrgConfig(BaseModel):
enabled: bool = False
limit: int = 10
class PaymentOrgConfig(BaseModel):
enabled: bool = True
stripe_key: str = ""
class DiscussionOrgConfig(BaseModel):
enabled: bool = True
limit: int = 10
class AnalyticsOrgConfig(BaseModel):
enabled: bool = True
limit: int = 10
class CollaborationOrgConfig(BaseModel):
enabled: bool = True
limit: int = 10
class APIOrgConfig(BaseModel):
enabled: bool = True
limit: int = 10
class OrgFeatureConfig(BaseModel):
courses: CourseOrgConfig = CourseOrgConfig()
members: MemberOrgConfig = MemberOrgConfig()
usergroups: UserGroupOrgConfig = UserGroupOrgConfig()
storage: StorageOrgConfig = StorageOrgConfig()
ai: AIOrgConfig = AIOrgConfig()
assignments: AssignmentOrgConfig = AssignmentOrgConfig()
payments: PaymentOrgConfig = PaymentOrgConfig()
discussions: DiscussionOrgConfig = DiscussionOrgConfig()
analytics: AnalyticsOrgConfig = AnalyticsOrgConfig()
collaboration: CollaborationOrgConfig = CollaborationOrgConfig()
api: APIOrgConfig = APIOrgConfig()
# General # General
class GeneralConfig(BaseModel): class OrgGeneralConfig(BaseModel):
color: str = "" enabled: bool = True
limits: LimitSettings = LimitSettings() color: str = "normal"
users: OrgUserConfig = OrgUserConfig() watermark: bool = True
collaboration: bool = False
active: bool = True
class OrganizationConfigBase(SQLModel): # Main Config
GeneralConfig: GeneralConfig class OrganizationConfigBase(BaseModel):
AIConfig: AIConfig config_version: str = "1.0"
general: OrgGeneralConfig
features: OrgFeatureConfig
class OrganizationConfig(SQLModel, table=True): class OrganizationConfig(SQLModel, table=True):
@ -56,7 +96,6 @@ class OrganizationConfig(SQLModel, table=True):
org_id: int = Field( org_id: int = Field(
sa_column=Column(BigInteger, ForeignKey("organization.id", ondelete="CASCADE")) sa_column=Column(BigInteger, ForeignKey("organization.id", ondelete="CASCADE"))
) )
# TODO: fix this to use the correct type GeneralConfig
config: dict = Field(default={}, sa_column=Column(JSON)) config: dict = Field(default={}, sa_column=Column(JSON))
creation_date: Optional[str] creation_date: Optional[str]
update_date: Optional[str] update_date: Optional[str]

View file

@ -86,8 +86,8 @@ def ai_start_activity_chat_session(
org_config = result.first() org_config = result.first()
org_config = OrganizationConfig.model_validate(org_config) org_config = OrganizationConfig.model_validate(org_config)
embeddings = org_config.config["AIConfig"]["embeddings"] embeddings = "text-embedding-ada-002"
ai_model = org_config.config["AIConfig"]["ai_model"] ai_model = org_config.config["features"]["ai"]["model"]
chat_session = get_chat_session_history() chat_session = get_chat_session_history()
@ -177,8 +177,8 @@ def ai_send_activity_chat_message(
org_config = result.first() org_config = result.first()
org_config = OrganizationConfig.model_validate(org_config) org_config = OrganizationConfig.model_validate(org_config)
embeddings = org_config.config["AIConfig"]["embeddings"] embeddings = "text-embedding-ada-002"
ai_model = org_config.config["AIConfig"]["ai_model"] ai_model = org_config.config["features"]["ai"]["model"]
chat_session = get_chat_session_history(chat_session_object.aichat_uuid) chat_session = get_chat_session_history(chat_session_object.aichat_uuid)

View file

@ -78,7 +78,7 @@ def check_limits_and_config(db_session: Session, organization: Organization):
) )
# Check if the Organization has Limits enabled and if the max_asks limit has been reached # Check if the Organization has Limits enabled and if the max_asks limit has been reached
if org_config.config["AIConfig"]["limits"]["limits_enabled"] == True: if org_config.config["features"]["ai"]["limit"] > 0:
LH_CONFIG = get_learnhouse_config() LH_CONFIG = get_learnhouse_config()
redis_conn_string = LH_CONFIG.redis_config.redis_connection_string redis_conn_string = LH_CONFIG.redis_config.redis_connection_string
@ -107,7 +107,7 @@ def check_limits_and_config(db_session: Session, organization: Organization):
ai_asks = int(ai_asks) ai_asks = int(ai_asks)
# Check if the Number of asks is less than the max_asks limit # Check if the Number of asks is less than the max_asks limit
if org_config.config["AIConfig"]["limits"]["max_asks"] <= ai_asks: if org_config.config["features"]["ai"]["limit"] <= ai_asks:
raise HTTPException( raise HTTPException(
status_code=403, status_code=403,
detail="Organization has reached the max number of AI asks", detail="Organization has reached the max number of AI asks",

View file

@ -5,12 +5,28 @@ from fastapi import HTTPException, Request
from sqlalchemy import desc from sqlalchemy import desc
from sqlmodel import Session, select from sqlmodel import Session, select
from src.db.install import Install, InstallRead from src.db.install import Install, InstallRead
from src.db.organization_config import AIEnabledFeatures, AILimitsSettings, LimitSettings, OrgUserConfig, OrganizationConfig, OrganizationConfigBase, GeneralConfig, AIConfig from src.db.organization_config import (
AIOrgConfig,
APIOrgConfig,
AnalyticsOrgConfig,
AssignmentOrgConfig,
CollaborationOrgConfig,
CourseOrgConfig,
DiscussionOrgConfig,
MemberOrgConfig,
OrgFeatureConfig,
OrgGeneralConfig,
OrganizationConfig,
OrganizationConfigBase,
PaymentOrgConfig,
StorageOrgConfig,
UserGroupOrgConfig,
)
from src.db.organizations import Organization, OrganizationCreate from src.db.organizations import Organization, OrganizationCreate
from src.db.roles import Permission, Rights, Role, RoleTypeEnum from src.db.roles import Permission, Rights, Role, RoleTypeEnum
from src.db.user_organizations import UserOrganization from src.db.user_organizations import UserOrganization
from src.db.users import User, UserCreate, UserRead from src.db.users import User, UserCreate, UserRead
from config.config import get_learnhouse_config from config.config import GeneralConfig, get_learnhouse_config
from src.security.security import security_hash_password from src.security.security import security_hash_password
@ -96,8 +112,7 @@ async def update_install_instance(
# Install Default roles # Install Default roles
def install_default_elements(db_session: Session): def install_default_elements(db_session: Session):
""" """ """
"""
# remove all default roles # remove all default roles
statement = select(Role).where(Role.role_type == RoleTypeEnum.TYPE_GLOBAL) statement = select(Role).where(Role.role_type == RoleTypeEnum.TYPE_GLOBAL)
roles = db_session.exec(statement).all() roles = db_session.exec(statement).all()
@ -300,9 +315,7 @@ def install_default_elements(db_session: Session):
# Organization creation # Organization creation
def install_create_organization( def install_create_organization(org_object: OrganizationCreate, db_session: Session):
org_object: OrganizationCreate, db_session: Session
):
org = Organization.model_validate(org_object) org = Organization.model_validate(org_object)
# Complete the org object # Complete the org object
@ -316,34 +329,26 @@ def install_create_organization(
# Org Config # Org Config
org_config = OrganizationConfigBase( org_config = OrganizationConfigBase(
GeneralConfig=GeneralConfig( config_version="1.0",
color="#000000", general=OrgGeneralConfig(
limits=LimitSettings(
limits_enabled=False,
max_users=0,
max_storage=0,
max_staff=0,
),
collaboration=False,
users=OrgUserConfig(
signup_mechanism="open",
),
active=True,
),
AIConfig=AIConfig(
enabled=True, enabled=True,
limits=AILimitsSettings( color="normal",
limits_enabled=False, watermark=True,
max_asks=0,
), ),
embeddings="text-embedding-ada-002", features=OrgFeatureConfig(
ai_model="gpt-3.5-turbo", courses=CourseOrgConfig(enabled=True, limit=0),
features=AIEnabledFeatures( members=MemberOrgConfig(
editor=True, enabled=True, signup_mode="open", admin_limit=0, limit=0
activity_ask=True,
course_ask=True,
global_ai_ask=True,
), ),
usergroups=UserGroupOrgConfig(enabled=True, limit=0),
storage=StorageOrgConfig(enabled=True, limit=0),
ai=AIOrgConfig(enabled=True, limit=0, model="text-embedding-ada-002"),
assignments=AssignmentOrgConfig(enabled=True, limit=0),
payments=PaymentOrgConfig(enabled=True, stripe_key=""),
discussions=DiscussionOrgConfig(enabled=True, limit=0),
analytics=AnalyticsOrgConfig(enabled=True, limit=0),
collaboration=CollaborationOrgConfig(enabled=True, limit=0),
api=APIOrgConfig(enabled=True, limit=0),
), ),
) )
@ -418,8 +423,6 @@ def install_create_organization_user(
db_session.commit() db_session.commit()
db_session.refresh(user) db_session.refresh(user)
# get org id # get org id
statement = select(Organization).where(Organization.slug == org_slug) statement = select(Organization).where(Organization.slug == org_slug)
org = db_session.exec(statement) org = db_session.exec(statement)

View file

@ -5,14 +5,21 @@ from typing import Literal
from uuid import uuid4 from uuid import uuid4
from sqlmodel import Session, select from sqlmodel import Session, select
from src.db.organization_config import ( from src.db.organization_config import (
AIConfig, AIOrgConfig,
AIEnabledFeatures, APIOrgConfig,
AILimitsSettings, AnalyticsOrgConfig,
GeneralConfig, AssignmentOrgConfig,
LimitSettings, CollaborationOrgConfig,
OrgUserConfig, CourseOrgConfig,
DiscussionOrgConfig,
MemberOrgConfig,
OrgFeatureConfig,
OrgGeneralConfig,
OrganizationConfig, OrganizationConfig,
OrganizationConfigBase, OrganizationConfigBase,
PaymentOrgConfig,
StorageOrgConfig,
UserGroupOrgConfig,
) )
from src.security.rbac.rbac import ( from src.security.rbac.rbac import (
authorization_verify_based_on_org_admin_status, authorization_verify_based_on_org_admin_status,
@ -149,35 +156,27 @@ async def create_org(
db_session.commit() db_session.commit()
db_session.refresh(user_org) db_session.refresh(user_org)
org_config = OrganizationConfigBase( org_config = org_config = OrganizationConfigBase(
GeneralConfig=GeneralConfig( config_version="1.0",
color="#000000", general=OrgGeneralConfig(
limits=LimitSettings(
limits_enabled=False,
max_users=0,
max_storage=0,
max_staff=0,
),
collaboration=False,
users=OrgUserConfig(
signup_mechanism="open",
),
active=True,
),
AIConfig=AIConfig(
enabled=True, enabled=True,
limits=AILimitsSettings( color="normal",
limits_enabled=False, watermark=True,
max_asks=0,
), ),
embeddings="text-embedding-ada-002", features=OrgFeatureConfig(
ai_model="gpt-3.5-turbo", courses=CourseOrgConfig(enabled=True, limit=0),
features=AIEnabledFeatures( members=MemberOrgConfig(
editor=True, enabled=True, signup_mode="open", admin_limit=0, limit=0
activity_ask=True,
course_ask=True,
global_ai_ask=True,
), ),
usergroups=UserGroupOrgConfig(enabled=True, limit=0),
storage=StorageOrgConfig(enabled=True, limit=0),
ai=AIOrgConfig(enabled=True, limit=0, model="text-embedding-ada-002"),
assignments=AssignmentOrgConfig(enabled=True, limit=0),
payments=PaymentOrgConfig(enabled=True, stripe_key=""),
discussions=DiscussionOrgConfig(enabled=True, limit=0),
analytics=AnalyticsOrgConfig(enabled=True, limit=0),
collaboration=CollaborationOrgConfig(enabled=True, limit=0),
api=APIOrgConfig(enabled=True, limit=0),
), ),
) )
@ -210,8 +209,6 @@ async def create_org(
return org return org
# Temporary pre-alpha code
async def create_org_with_config( async def create_org_with_config(
request: Request, request: Request,
org_object: OrganizationCreate, org_object: OrganizationCreate,
@ -477,7 +474,7 @@ async def update_org_signup_mechanism(
# Update config # Update config
updated_config = OrganizationConfigBase(**updated_config) updated_config = OrganizationConfigBase(**updated_config)
updated_config.GeneralConfig.users.signup_mechanism = signup_mechanism updated_config.features.members.signup_mode = signup_mechanism
# Update the database # Update the database
org_config.config = json.loads(updated_config.json()) org_config.config = json.loads(updated_config.json())
@ -527,7 +524,7 @@ async def get_org_join_mechanism(
# Get the signup mechanism # Get the signup mechanism
config = OrganizationConfigBase(**config) config = OrganizationConfigBase(**config)
signup_mechanism = config.GeneralConfig.users.signup_mechanism signup_mechanism = config.features.members.signup_mode
return signup_mechanism return signup_mechanism