Skip to content

Commit

Permalink
fix: fix user model
Browse files Browse the repository at this point in the history
  • Loading branch information
joboy-dev committed Aug 10, 2024
1 parent 6f5695c commit 1c899ff
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 22 deletions.
26 changes: 26 additions & 0 deletions alembic/versions/e63f024c23eb_merge_heads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""merge heads
Revision ID: e63f024c23eb
Revises: 0c0978bc2925, 3f455aaf9065
Create Date: 2024-08-10 11:54:28.435165
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = 'e63f024c23eb'
down_revision: Union[str, None] = ('0c0978bc2925', '3f455aaf9065')
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
pass


def downgrade() -> None:
pass
11 changes: 5 additions & 6 deletions api/v1/models/organisation.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@

""" The Organisation model
"""
from sqlalchemy import Column, String, Text, Enum
from sqlalchemy import Column, String
from sqlalchemy.orm import relationship
from api.v1.models.associations import user_organisation_association
from api.v1.models.permissions.user_org_role import user_organisation_roles
from api.v1.models.base_model import BaseTableModel


class Organisation(BaseTableModel):
__tablename__ = "organisations"

name = Column(String, nullable=False, unique=True)
name = Column(String, nullable=False, unique=False)
email = Column(String, nullable=True, unique=True)
industry = Column(String, nullable=True)
type = Column(String, nullable=True)
Expand All @@ -20,7 +20,7 @@ class Organisation(BaseTableModel):
address = Column(String, nullable=True)

users = relationship(
"User", secondary=user_organisation_association, back_populates="organisations"
"User", secondary=user_organisation_roles, back_populates="organisations"
)
billing_plans = relationship("BillingPlan", back_populates="organisation", cascade="all, delete-orphan")
invitations = relationship("Invitation", back_populates="organisation", cascade="all, delete-orphan")
Expand All @@ -36,8 +36,7 @@ class Organisation(BaseTableModel):
products = relationship(
"Product", back_populates="organisation", cascade="all, delete-orphan"
)
sales = relationship('Sales', back_populates='organisation',
cascade='all, delete-orphan')
sales = relationship('Sales', back_populates='organisation', cascade='all, delete-orphan')

def __str__(self):
return self.name
8 changes: 5 additions & 3 deletions api/v1/models/permissions/permissions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from sqlalchemy import Column, String
from api.v1.models.base_model import BaseTableModel
from uuid_extensions import uuid7
from api.v1.models.permissions.role_permissions import role_permissions
from sqlalchemy.orm import relationship

class Permission(BaseTableModel):
__tablename__ = 'permissions'

title = Column(String, unique=True, nullable=False)

title = Column(String, unique=True, nullable=False)

role = relationship('Role', secondary=role_permissions, back_populates='permissions')
5 changes: 4 additions & 1 deletion api/v1/models/permissions/role.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from sqlalchemy import Column, String, Boolean, Text
from sqlalchemy.orm import relationship
from api.v1.models.base_model import BaseTableModel
from uuid_extensions import uuid7
from api.v1.models.permissions.role_permissions import role_permissions

class Role(BaseTableModel):
__tablename__ = 'roles'

name = Column(String, unique=True, nullable=False)
description = Column(Text, nullable=True)
is_builtin = Column(Boolean, default=False) # True for built-in roles, False for custom roles

permissions = relationship('Permission', secondary=role_permissions, back_populates='role')
3 changes: 2 additions & 1 deletion api/v1/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from sqlalchemy import Column, String, text, Boolean
from sqlalchemy.orm import relationship
from api.v1.models.associations import user_organisation_association
from api.v1.models.permissions.user_org_role import user_organisation_roles
from api.v1.models.base_model import BaseTableModel


Expand All @@ -24,7 +25,7 @@ class User(BaseTableModel):
"Profile", uselist=False, back_populates="user", cascade="all, delete-orphan"
)
organisations = relationship(
"Organisation", secondary=user_organisation_association, back_populates="users"
"Organisation", secondary=user_organisation_roles, back_populates="users"
)
notifications = relationship(
"Notification", back_populates="user", cascade="all, delete-orphan"
Expand Down
6 changes: 3 additions & 3 deletions api/v1/routes/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ def register(background_tasks: BackgroundTasks, response: Response, user_schema:
user = user_service.create(db=db, schema=user_schema)

# create an organization for the user
org = CreateUpdateOrganization(
name=f"{user.first_name}'s Organization",
org = CreateUpdateOrganisation(
name=f"{user.first_name}'s Organisation",
email=user.email
)
user_org = organization_service.create(db=db, schema=org, user=user)
user_org = organisation_service.create(db=db, schema=org, user=user)

# Create access and refresh tokens
access_token = user_service.create_access_token(user_id=user.id)
Expand Down
1 change: 0 additions & 1 deletion api/v1/routes/google_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

from api.db.database import get_db
from api.core.dependencies.google_oauth_config import google_oauth
from api.v1.schemas.organization import CreateUpdateOrganization
from api.v1.services.google_oauth import GoogleOauthServices
from api.utils.success_response import success_response
from api.v1.schemas.google_oauth import OAuthToken
Expand Down
23 changes: 19 additions & 4 deletions api/v1/services/organisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
from api.core.base.services import Service
from api.utils.db_validators import check_model_existence, check_user_in_org
from api.utils.pagination import paginated_response
from api.v1.models.permissions.role import Role
from api.v1.models.product import Product
from api.v1.models.associations import user_organisation_association
from api.v1.models.permissions.user_org_role import user_organisation_roles
from api.v1.models.organisation import Organisation
from api.v1.models.user import User
from api.v1.schemas.organisation import (
Expand All @@ -23,23 +25,36 @@
class OrganisationService(Service):
"""Organisation service functionality"""

def get_role_id(self, db: Session, role: str):
'''Returns the role id associated with a role'''

role_ = db.query(Role).filter(Role.name == role).first()

if not role_:
raise HTTPException(status_code=404, detail="Admin role not found")

return role_.id


def create(self, db: Session, schema: CreateUpdateOrganisation, user: User):
"""Create a new product"""

# Create a new organisation
new_organisation = Organisation(**schema.model_dump())

email = schema.model_dump()["email"]
name = schema.model_dump()["name"]
self.check_by_email(db, email)
self.check_by_name(db, name)

db.add(new_organisation)
db.commit()
db.refresh(new_organisation)

# Add user as owner to the new organisation
stmt = user_organisation_association.insert().values(
user_id=user.id, organisation_id=new_organisation.id, role="owner"
stmt = user_organisation_roles.insert().values(
user_id=user.id,
organisation_id=new_organisation.id,
role_id=self.get_role_id(db=db, role='admin'),
is_owner=True
)
db.execute(stmt)
db.commit()
Expand Down
3 changes: 1 addition & 2 deletions api/v1/services/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def create(self, db: Session, schema: user.UserCreate):
if db.query(User).filter(User.email == schema.email).first():
raise HTTPException(
status_code=400,
detail="User with this email or username already exists",
detail="User with this email already exists",
)

# Hash password
Expand All @@ -152,7 +152,6 @@ def create(self, db: Session, schema: user.UserCreate):
notification_setting_service.create(db=db, user=user)

# create data privacy setting

data_privacy = DataPrivacySetting(user_id=user.id)

db.add(data_privacy)
Expand Down
4 changes: 3 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import uvicorn
from fastapi.staticfiles import StaticFiles
import uvicorn, os
Expand All @@ -18,10 +17,13 @@
from api.utils.logger import logger
from api.v1.routes import api_version_one
from api.utils.settings import settings
from scripts.populate_db import populate_roles_and_permissions


@asynccontextmanager
async def lifespan(app: FastAPI):
'''Lifespan function'''

yield


Expand Down
60 changes: 60 additions & 0 deletions scripts/populate_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from api.db.database import get_db
from api.v1.models.permissions.role import Role
from api.v1.models.permissions.permissions import Permission

db = next(get_db())

def populate_roles_and_permissions():
'''Function to populate database with roles and permissions'''

# Define roles
roles = [
{"name": "admin", "description": "Administrator with full access", "is_builtin": True},
{"name": "user", "description": "Regular user with limited access", "is_builtin": True},
# {"name": "Manager", "description": "Manager with management access", "is_builtin": False},
]

# Define permissions
permissions = [
{"title": "create_user"},
{"title": "delete_user"},
{"title": "update_user"},
{"title": "view_user"},
{"title": "manage_organisation"},
{"title": "delete_organisation"},
]

# Insert roles into the database
for role_data in roles:
if not db.query(Role).filter(Role.name == role_data['name']).first():
role = Role(
name=role_data["name"],
description=role_data["description"],
is_builtin=role_data["is_builtin"]
)
db.add(role)
db.commit()
db.refresh(role)

# Insert permissions into the database
for perm_data in permissions:
if not db.query(Permission).filter(Permission.title == perm_data['title']).first():
permission = Permission(title=perm_data["title"])
db.add(permission)
db.commit()
db.refresh(permission)

# Assign permissions to roles (example)
admin_role = db.query(Role).filter_by(name="admin").first()
user_role = db.query(Role).filter_by(name="user").first()

if not admin_role and not user_role:
admin_permissions = db.query(Permission).all()
user_permissions = db.query(Permission).filter(Permission.title == "view_user").all()

admin_role.permissions.extend(admin_permissions)
user_role.permissions.extend(user_permissions)

db.commit()

db.close()

0 comments on commit 1c899ff

Please sign in to comment.