Updated with audit table

This commit is contained in:
Saurab-Shrestha 2024-02-25 09:54:56 +05:45
parent 493963908d
commit 808a0fa6fc
11 changed files with 124 additions and 14 deletions

View File

@ -0,0 +1,32 @@
"""added password expiry
Revision ID: b7b23e5d5214
Revises: 62c1a29320fc
Create Date: 2024-02-24 19:47:49.069873
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'b7b23e5d5214'
down_revision: Union[str, None] = '62c1a29320fc'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
# op.create_unique_constraint('unique_user_role', 'user_roles', ['user_id', 'role_id', 'company_id'])
op.add_column('users', sa.Column('password_created', sa.DateTime(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('users', 'password_created')
# op.drop_constraint('unique_user_role', 'user_roles', type_='unique')
# ### end Alembic commands ###

View File

@ -220,7 +220,6 @@ def ingest_file(
object="list", model="private-gpt", data=ingested_documents)
log_audit(model='Document', action='create',
details={
'status': '200',
'filename': file.filename,
'user': current_user.fullname,
}, user_id=current_user.id)
@ -242,7 +241,6 @@ def ingest_file(
async def common_ingest_logic(
request: Request,
db: Session,
ocr_file,
current_user,
@ -274,10 +272,10 @@ async def common_ingest_logic(
with open(upload_path, "wb") as f:
f.write(file.read())
file.seek(0) # Move the file pointer back to the beginning
file.seek(0)
ingested_documents = service.ingest_bin_data(file_name, file)
log_audit(model='Document', action='create',
details={'status': 200, 'message': "file uploaded successfully."}, user_id=current_user.id)
details={'status': "SUCCESS", 'message': f"{file_name} uploaded successfully."}, user_id=current_user.id)
logger.info(
f"{file_name} is uploaded by the {current_user.fullname}.")

View File

@ -139,3 +139,11 @@ def get_audit_logger(request: Request, db: Session = Depends(get_db)):
return lambda model, action, details, user_id=None: log_audit_entry(db, model, action, details, user_id)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error in get_audit_logger: {str(e)}")
def get_current_active_user(
current_user: models.User = Security(get_current_user, scopes=[],),
) -> models.User:
if not crud.user.is_active(current_user):
raise HTTPException(status_code=400, detail="Inactive user")
return current_user

View File

@ -169,7 +169,7 @@ def login_access_token(
"user": token_payload,
"token_type": "bearer",
}
log_audit(model='User', action='update',
log_audit(model='User', action='login',
details=token_payload, user_id=user.id)
return JSONResponse(content=response_dict)
@ -213,7 +213,7 @@ def register(
role_name: str = Body(None, title="Role Name",
description="User role name (if applicable)"),
current_user: models.User = Security(
deps.get_current_user,
deps.get_current_active_user,
scopes=[Role.ADMIN["name"], Role.SUPER_ADMIN["name"]],
),
) -> Any:

View File

@ -45,8 +45,31 @@ def list_departments(
"""
Retrieve a list of departments with pagination support.
"""
departments = crud.department.get_multi(db, skip=skip, limit=limit)
return departments
try:
role = current_user.user_role.role.name if current_user.user_role else None
if role == "SUPER_ADMIN":
deps = crud.department.get_multi(db, skip=skip, limit=limit)
else:
deps = crud.department.get_multi_department(
db, department_id=current_user.department_id, skip=skip, limit=limit)
deps = [
schemas.Department(
id=dep.id,
name=dep.name,
total_users=dep.total_users,
total_documents=dep.total_documents,
)
for dep in deps
]
return deps
except Exception as e:
print(traceback.format_exc())
logger.error(f"There was an error listing the file(s).")
raise HTTPException(
status_code=500,
detail="Internal Server Error",
)
@router.post("/create", response_model=schemas.Department)

View File

@ -7,7 +7,7 @@ from typing import Dict, Any, Optional, Union
from jose import JWTError, jwt
from passlib.context import CryptContext
ACCESS_TOKEN_EXPIRE_MINUTES = 120 # 30 minutes
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 12 # 12 hrs
REFRESH_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 # 7 days
ALGORITHM = "HS256"
# JWT_SECRET_KEY = os.environ['JWT_SECRET_KEY'] # should be kept secret

View File

@ -2,7 +2,7 @@ from sqlalchemy.orm import Session
from private_gpt.users.schemas.department import DepartmentCreate, DepartmentUpdate
from private_gpt.users.models.department import Department
from private_gpt.users.crud.base import CRUDBase
from typing import Optional
from typing import Optional, List
class CRUDDepartments(CRUDBase[Department, DepartmentCreate, DepartmentUpdate]):
@ -12,4 +12,16 @@ class CRUDDepartments(CRUDBase[Department, DepartmentCreate, DepartmentUpdate]):
def get_by_department_name(self, db: Session, *, name: str) -> Optional[Department]:
return db.query(self.model).filter(Department.name == name).first()
def get_multi_department(
self, db: Session, *, department_id: int, skip: int = 0, limit: int = 100
) -> List[Department]:
return (
db.query(self.model)
.filter(Department.department_id == department_id)
.offset(skip)
.limit(limit)
.all()
)
department = CRUDDepartments(Department)

View File

@ -13,6 +13,7 @@ from sqlalchemy import event, func, select, update
from sqlalchemy.orm import relationship
from private_gpt.users.db.base_class import Base
from private_gpt.users.models.department import Department
class User(Base):
"""Models a user table"""
__tablename__ = "users"
@ -34,6 +35,8 @@ class User(Base):
default=datetime.datetime.utcnow,
onupdate=datetime.datetime.utcnow,
)
password_created = Column(DateTime, nullable=True)
company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)
company = relationship("Company", back_populates="users")
@ -72,3 +75,29 @@ def update_total_users(mapper, connection, target):
)
@event.listens_for(User, 'before_insert')
def set_password_created(mapper, connection, target):
target.password_created = datetime.datetime.utcnow()
connection.execute(
update(User)
.values(password_created=datetime.datetime.utcnow())
.where(User.id == target.id)
)
@event.listens_for(User, 'before_update', propagate=True)
def check_password_expiry(mapper, connection, target):
if target.password_created and (
datetime.datetime.utcnow() - target.password_created).days > 90:
target.is_active = False
connection.execute(
update(User)
.values(is_active=False)
.where(User.id == target.id)
)
else:
connection.execute(
update(User)
.values(is_active=True)
.where(User.id == target.id)
)

View File

@ -1,6 +1,6 @@
from .role import Role, RoleCreate, RoleInDB, RoleUpdate
from .token import TokenSchema, TokenPayload
from .user import User, UserCreate, UserInDB, UserUpdate, UserBaseSchema, Profile, UsernameUpdate, DeleteUser, UserAdminUpdate, UserAdmin
from .user import User, UserCreate, UserInDB, UserUpdate, UserBaseSchema, Profile, UsernameUpdate, DeleteUser, UserAdminUpdate, UserAdmin, PasswordUpdate
from .user_role import UserRole, UserRoleCreate, UserRoleInDB, UserRoleUpdate
from .subscription import Subscription, SubscriptionBase, SubscriptionCreate, SubscriptionUpdate
from .company import Company, CompanyBase, CompanyCreate, CompanyUpdate

View File

@ -33,6 +33,10 @@ class DepartmentAdminCreate(DepartmentBase):
class Config:
orm_mode = True
class Department(DepartmentInDB):
pass
class Department(BaseModel):
id: int
name: str
total_users: Optional[int]
total_documents: Optional[int]

View File

@ -75,4 +75,8 @@ class UserAdminUpdate(BaseModel):
class UserAdmin(BaseModel):
fullname: str
department_id: int
department_id: int
class PasswordUpdate(BaseModel):
password_created: Optional[datetime] = None