mirror of
https://github.com/imartinez/privateGPT.git
synced 2025-07-04 19:18:13 +00:00
Updated with audit table
This commit is contained in:
parent
493963908d
commit
808a0fa6fc
32
alembic/versions/b7b23e5d5214_added_password_expiry.py
Normal file
32
alembic/versions/b7b23e5d5214_added_password_expiry.py
Normal 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 ###
|
@ -220,7 +220,6 @@ def ingest_file(
|
|||||||
object="list", model="private-gpt", data=ingested_documents)
|
object="list", model="private-gpt", data=ingested_documents)
|
||||||
log_audit(model='Document', action='create',
|
log_audit(model='Document', action='create',
|
||||||
details={
|
details={
|
||||||
'status': '200',
|
|
||||||
'filename': file.filename,
|
'filename': file.filename,
|
||||||
'user': current_user.fullname,
|
'user': current_user.fullname,
|
||||||
}, user_id=current_user.id)
|
}, user_id=current_user.id)
|
||||||
@ -242,7 +241,6 @@ def ingest_file(
|
|||||||
|
|
||||||
async def common_ingest_logic(
|
async def common_ingest_logic(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|
||||||
db: Session,
|
db: Session,
|
||||||
ocr_file,
|
ocr_file,
|
||||||
current_user,
|
current_user,
|
||||||
@ -274,10 +272,10 @@ async def common_ingest_logic(
|
|||||||
|
|
||||||
with open(upload_path, "wb") as f:
|
with open(upload_path, "wb") as f:
|
||||||
f.write(file.read())
|
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)
|
ingested_documents = service.ingest_bin_data(file_name, file)
|
||||||
log_audit(model='Document', action='create',
|
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(
|
logger.info(
|
||||||
f"{file_name} is uploaded by the {current_user.fullname}.")
|
f"{file_name} is uploaded by the {current_user.fullname}.")
|
||||||
|
@ -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)
|
return lambda model, action, details, user_id=None: log_audit_entry(db, model, action, details, user_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Error in get_audit_logger: {str(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
|
||||||
|
@ -169,7 +169,7 @@ def login_access_token(
|
|||||||
"user": token_payload,
|
"user": token_payload,
|
||||||
"token_type": "bearer",
|
"token_type": "bearer",
|
||||||
}
|
}
|
||||||
log_audit(model='User', action='update',
|
log_audit(model='User', action='login',
|
||||||
details=token_payload, user_id=user.id)
|
details=token_payload, user_id=user.id)
|
||||||
return JSONResponse(content=response_dict)
|
return JSONResponse(content=response_dict)
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ def register(
|
|||||||
role_name: str = Body(None, title="Role Name",
|
role_name: str = Body(None, title="Role Name",
|
||||||
description="User role name (if applicable)"),
|
description="User role name (if applicable)"),
|
||||||
current_user: models.User = Security(
|
current_user: models.User = Security(
|
||||||
deps.get_current_user,
|
deps.get_current_active_user,
|
||||||
scopes=[Role.ADMIN["name"], Role.SUPER_ADMIN["name"]],
|
scopes=[Role.ADMIN["name"], Role.SUPER_ADMIN["name"]],
|
||||||
),
|
),
|
||||||
) -> Any:
|
) -> Any:
|
||||||
|
@ -45,8 +45,31 @@ def list_departments(
|
|||||||
"""
|
"""
|
||||||
Retrieve a list of departments with pagination support.
|
Retrieve a list of departments with pagination support.
|
||||||
"""
|
"""
|
||||||
departments = crud.department.get_multi(db, skip=skip, limit=limit)
|
try:
|
||||||
return departments
|
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)
|
@router.post("/create", response_model=schemas.Department)
|
||||||
|
@ -7,7 +7,7 @@ from typing import Dict, Any, Optional, Union
|
|||||||
from jose import JWTError, jwt
|
from jose import JWTError, jwt
|
||||||
from passlib.context import CryptContext
|
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
|
REFRESH_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 # 7 days
|
||||||
ALGORITHM = "HS256"
|
ALGORITHM = "HS256"
|
||||||
# JWT_SECRET_KEY = os.environ['JWT_SECRET_KEY'] # should be kept secret
|
# JWT_SECRET_KEY = os.environ['JWT_SECRET_KEY'] # should be kept secret
|
||||||
|
@ -2,7 +2,7 @@ from sqlalchemy.orm import Session
|
|||||||
from private_gpt.users.schemas.department import DepartmentCreate, DepartmentUpdate
|
from private_gpt.users.schemas.department import DepartmentCreate, DepartmentUpdate
|
||||||
from private_gpt.users.models.department import Department
|
from private_gpt.users.models.department import Department
|
||||||
from private_gpt.users.crud.base import CRUDBase
|
from private_gpt.users.crud.base import CRUDBase
|
||||||
from typing import Optional
|
from typing import Optional, List
|
||||||
|
|
||||||
|
|
||||||
class CRUDDepartments(CRUDBase[Department, DepartmentCreate, DepartmentUpdate]):
|
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]:
|
def get_by_department_name(self, db: Session, *, name: str) -> Optional[Department]:
|
||||||
return db.query(self.model).filter(Department.name == name).first()
|
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)
|
department = CRUDDepartments(Department)
|
||||||
|
@ -13,6 +13,7 @@ from sqlalchemy import event, func, select, update
|
|||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from private_gpt.users.db.base_class import Base
|
from private_gpt.users.db.base_class import Base
|
||||||
from private_gpt.users.models.department import Department
|
from private_gpt.users.models.department import Department
|
||||||
|
|
||||||
class User(Base):
|
class User(Base):
|
||||||
"""Models a user table"""
|
"""Models a user table"""
|
||||||
__tablename__ = "users"
|
__tablename__ = "users"
|
||||||
@ -35,6 +36,8 @@ class User(Base):
|
|||||||
onupdate=datetime.datetime.utcnow,
|
onupdate=datetime.datetime.utcnow,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
password_created = Column(DateTime, nullable=True)
|
||||||
|
|
||||||
company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)
|
company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)
|
||||||
company = relationship("Company", back_populates="users")
|
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)
|
||||||
|
)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from .role import Role, RoleCreate, RoleInDB, RoleUpdate
|
from .role import Role, RoleCreate, RoleInDB, RoleUpdate
|
||||||
from .token import TokenSchema, TokenPayload
|
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 .user_role import UserRole, UserRoleCreate, UserRoleInDB, UserRoleUpdate
|
||||||
from .subscription import Subscription, SubscriptionBase, SubscriptionCreate, SubscriptionUpdate
|
from .subscription import Subscription, SubscriptionBase, SubscriptionCreate, SubscriptionUpdate
|
||||||
from .company import Company, CompanyBase, CompanyCreate, CompanyUpdate
|
from .company import Company, CompanyBase, CompanyCreate, CompanyUpdate
|
||||||
|
@ -33,6 +33,10 @@ class DepartmentAdminCreate(DepartmentBase):
|
|||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
class Department(DepartmentInDB):
|
class Department(BaseModel):
|
||||||
pass
|
id: int
|
||||||
|
name: str
|
||||||
|
total_users: Optional[int]
|
||||||
|
total_documents: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,3 +76,7 @@ class UserAdminUpdate(BaseModel):
|
|||||||
class UserAdmin(BaseModel):
|
class UserAdmin(BaseModel):
|
||||||
fullname: str
|
fullname: str
|
||||||
department_id: int
|
department_id: int
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordUpdate(BaseModel):
|
||||||
|
password_created: Optional[datetime] = None
|
||||||
|
Loading…
Reference in New Issue
Block a user