Spaces:
Running
Running
vanitha commited on
Commit ·
5fdb9fd
1
Parent(s): 42e40ce
changed user_id as UUID
Browse files
app/nosql.py
CHANGED
|
@@ -41,7 +41,12 @@ class DatabaseConnection:
|
|
| 41 |
|
| 42 |
logger.info(f"Connecting to MongoDB: {mongodb_uri}")
|
| 43 |
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
cls._db = cls._client[settings.MONGODB_DB_NAME]
|
| 46 |
|
| 47 |
# Test the connection
|
|
|
|
| 41 |
|
| 42 |
logger.info(f"Connecting to MongoDB: {mongodb_uri}")
|
| 43 |
|
| 44 |
+
|
| 45 |
+
cls._client = AsyncIOMotorClient(
|
| 46 |
+
mongodb_uri,
|
| 47 |
+
uuidRepresentation="standard"
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
cls._db = cls._client[settings.MONGODB_DB_NAME]
|
| 51 |
|
| 52 |
# Test the connection
|
app/system_users/controllers/router.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
from pydantic import BaseModel, Field
|
| 2 |
from fastapi import APIRouter, Depends, HTTPException, status, Request
|
| 3 |
from fastapi.security import HTTPAuthorizationCredentials
|
|
@@ -436,7 +437,7 @@ async def list_users_with_projection(
|
|
| 436 |
|
| 437 |
@router.get("/users/{user_id}", response_model=UserInfoResponse)
|
| 438 |
async def get_user_by_id(
|
| 439 |
-
user_id:
|
| 440 |
current_user: SystemUserModel = Depends(require_admin_role),
|
| 441 |
user_service: SystemUserService = Depends(get_system_user_service)
|
| 442 |
):
|
|
@@ -480,7 +481,7 @@ async def get_user_by_id(
|
|
| 480 |
|
| 481 |
@router.put("/users/{user_id}", response_model=UserInfoResponse)
|
| 482 |
async def update_user(
|
| 483 |
-
user_id:
|
| 484 |
update_data: UpdateUserRequest,
|
| 485 |
current_user: SystemUserModel = Depends(require_admin_role),
|
| 486 |
user_service: SystemUserService = Depends(get_system_user_service)
|
|
@@ -764,7 +765,7 @@ async def reset_password(
|
|
| 764 |
|
| 765 |
@router.delete("/users/{user_id}", response_model=StandardResponse)
|
| 766 |
async def deactivate_user(
|
| 767 |
-
user_id:
|
| 768 |
current_user: SystemUserModel = Depends(require_admin_role),
|
| 769 |
user_service: SystemUserService = Depends(get_system_user_service)
|
| 770 |
):
|
|
|
|
| 1 |
+
from uuid import UUID
|
| 2 |
from pydantic import BaseModel, Field
|
| 3 |
from fastapi import APIRouter, Depends, HTTPException, status, Request
|
| 4 |
from fastapi.security import HTTPAuthorizationCredentials
|
|
|
|
| 437 |
|
| 438 |
@router.get("/users/{user_id}", response_model=UserInfoResponse)
|
| 439 |
async def get_user_by_id(
|
| 440 |
+
user_id: UUID,
|
| 441 |
current_user: SystemUserModel = Depends(require_admin_role),
|
| 442 |
user_service: SystemUserService = Depends(get_system_user_service)
|
| 443 |
):
|
|
|
|
| 481 |
|
| 482 |
@router.put("/users/{user_id}", response_model=UserInfoResponse)
|
| 483 |
async def update_user(
|
| 484 |
+
user_id: UUID,
|
| 485 |
update_data: UpdateUserRequest,
|
| 486 |
current_user: SystemUserModel = Depends(require_admin_role),
|
| 487 |
user_service: SystemUserService = Depends(get_system_user_service)
|
|
|
|
| 765 |
|
| 766 |
@router.delete("/users/{user_id}", response_model=StandardResponse)
|
| 767 |
async def deactivate_user(
|
| 768 |
+
user_id: UUID,
|
| 769 |
current_user: SystemUserModel = Depends(require_admin_role),
|
| 770 |
user_service: SystemUserService = Depends(get_system_user_service)
|
| 771 |
):
|
app/system_users/models/model.py
CHANGED
|
@@ -4,6 +4,7 @@ Represents a system user with login credentials and permissions.
|
|
| 4 |
"""
|
| 5 |
from datetime import datetime
|
| 6 |
from typing import Optional, Dict, Any, List
|
|
|
|
| 7 |
from pydantic import BaseModel, Field, EmailStr
|
| 8 |
from enum import Enum
|
| 9 |
|
|
@@ -53,7 +54,7 @@ class SystemUserModel(BaseModel):
|
|
| 53 |
System User data model for authentication and authorization.
|
| 54 |
Represents the complete user document in MongoDB.
|
| 55 |
"""
|
| 56 |
-
user_id:
|
| 57 |
username: str = Field(..., description="Unique username (lowercase alphanumeric)")
|
| 58 |
email: EmailStr = Field(..., description="User email address")
|
| 59 |
merchant_id: str = Field(..., description="User Merchant Information")
|
|
|
|
| 4 |
"""
|
| 5 |
from datetime import datetime
|
| 6 |
from typing import Optional, Dict, Any, List
|
| 7 |
+
from uuid import UUID
|
| 8 |
from pydantic import BaseModel, Field, EmailStr
|
| 9 |
from enum import Enum
|
| 10 |
|
|
|
|
| 54 |
System User data model for authentication and authorization.
|
| 55 |
Represents the complete user document in MongoDB.
|
| 56 |
"""
|
| 57 |
+
user_id: UUID = Field(..., description="Unique user identifier (UUID/ULID)")
|
| 58 |
username: str = Field(..., description="Unique username (lowercase alphanumeric)")
|
| 59 |
email: EmailStr = Field(..., description="User email address")
|
| 60 |
merchant_id: str = Field(..., description="User Merchant Information")
|
app/system_users/schemas/schema.py
CHANGED
|
@@ -3,6 +3,7 @@ System User schemas for request/response models.
|
|
| 3 |
"""
|
| 4 |
from datetime import datetime
|
| 5 |
from typing import Optional, List, Dict, Any
|
|
|
|
| 6 |
from pydantic import BaseModel, Field, EmailStr, validator
|
| 7 |
from app.system_users.models.model import UserStatus, UserRole
|
| 8 |
|
|
@@ -24,7 +25,7 @@ class LoginResponse(BaseModel):
|
|
| 24 |
|
| 25 |
class UserInfoResponse(BaseModel):
|
| 26 |
"""User information response schema."""
|
| 27 |
-
user_id:
|
| 28 |
username: str = Field(..., description="Username")
|
| 29 |
email: str = Field(..., description="Email address")
|
| 30 |
merchant_id: str = Field(..., description="Merchant ID")
|
|
|
|
| 3 |
"""
|
| 4 |
from datetime import datetime
|
| 5 |
from typing import Optional, List, Dict, Any
|
| 6 |
+
from uuid import UUID
|
| 7 |
from pydantic import BaseModel, Field, EmailStr, validator
|
| 8 |
from app.system_users.models.model import UserStatus, UserRole
|
| 9 |
|
|
|
|
| 25 |
|
| 26 |
class UserInfoResponse(BaseModel):
|
| 27 |
"""User information response schema."""
|
| 28 |
+
user_id: UUID = Field(..., description="Unique user identifier")
|
| 29 |
username: str = Field(..., description="Username")
|
| 30 |
email: str = Field(..., description="Email address")
|
| 31 |
merchant_id: str = Field(..., description="Merchant ID")
|
app/system_users/services/service.py
CHANGED
|
@@ -4,6 +4,8 @@ System User service for authentication and user management.
|
|
| 4 |
import secrets
|
| 5 |
from datetime import datetime, timedelta
|
| 6 |
from typing import Optional, List, Dict, Any, Tuple
|
|
|
|
|
|
|
| 7 |
from motor.motor_asyncio import AsyncIOMotorDatabase
|
| 8 |
from passlib.context import CryptContext
|
| 9 |
from jose import JWTError, jwt
|
|
@@ -116,7 +118,7 @@ class SystemUserService:
|
|
| 116 |
logger.warning(f"Token verification failed: {e}")
|
| 117 |
return None
|
| 118 |
|
| 119 |
-
async def get_user_by_id(self, user_id:
|
| 120 |
"""Get user by user_id."""
|
| 121 |
try:
|
| 122 |
user_doc = await self.collection.find_one({"user_id": user_id})
|
|
@@ -179,8 +181,8 @@ class SystemUserService:
|
|
| 179 |
)
|
| 180 |
|
| 181 |
# Generate user ID
|
| 182 |
-
user_id = f"usr_{secrets.token_urlsafe(16)}"
|
| 183 |
-
|
| 184 |
# Hash password
|
| 185 |
password_hash = self.get_password_hash(user_data.password)
|
| 186 |
|
|
@@ -194,7 +196,7 @@ class SystemUserService:
|
|
| 194 |
|
| 195 |
# Create user model
|
| 196 |
user_model = SystemUserModel(
|
| 197 |
-
user_id=user_id,
|
| 198 |
username=user_data.username.lower(),
|
| 199 |
email=user_data.email.lower(),
|
| 200 |
merchant_id=user_data.merchant_id,
|
|
@@ -206,12 +208,17 @@ class SystemUserService:
|
|
| 206 |
role=user_data.role,
|
| 207 |
permissions=user_data.permissions,
|
| 208 |
status=UserStatus.ACTIVE, # Set as active by default
|
| 209 |
-
created_by=created_by,
|
| 210 |
created_at=datetime.utcnow()
|
| 211 |
)
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 215 |
|
| 216 |
logger.info(f"User created successfully: {user_id}")
|
| 217 |
return user_model
|
|
@@ -470,7 +477,7 @@ class SystemUserService:
|
|
| 470 |
"warning_threshold_days": warning_threshold
|
| 471 |
}
|
| 472 |
|
| 473 |
-
async def mark_password_change_required(self, user_id:
|
| 474 |
"""
|
| 475 |
Mark that a user must change their password.
|
| 476 |
|
|
@@ -519,7 +526,7 @@ class SystemUserService:
|
|
| 519 |
logger.error(f"Error marking password change required for {user_id}: {e}")
|
| 520 |
return False
|
| 521 |
|
| 522 |
-
async def record_password_change(self, user_id:
|
| 523 |
"""
|
| 524 |
Record password change for rotation policy compliance.
|
| 525 |
|
|
@@ -593,7 +600,7 @@ class SystemUserService:
|
|
| 593 |
logger.error(f"Error updating user {user_id}: {e}")
|
| 594 |
return None
|
| 595 |
|
| 596 |
-
async def change_password(self, user_id:
|
| 597 |
"""Change user password."""
|
| 598 |
try:
|
| 599 |
user = await self.get_user_by_id(user_id)
|
|
|
|
| 4 |
import secrets
|
| 5 |
from datetime import datetime, timedelta
|
| 6 |
from typing import Optional, List, Dict, Any, Tuple
|
| 7 |
+
from uuid import UUID
|
| 8 |
+
import uuid
|
| 9 |
from motor.motor_asyncio import AsyncIOMotorDatabase
|
| 10 |
from passlib.context import CryptContext
|
| 11 |
from jose import JWTError, jwt
|
|
|
|
| 118 |
logger.warning(f"Token verification failed: {e}")
|
| 119 |
return None
|
| 120 |
|
| 121 |
+
async def get_user_by_id(self, user_id: UUID) -> Optional[SystemUserModel]:
|
| 122 |
"""Get user by user_id."""
|
| 123 |
try:
|
| 124 |
user_doc = await self.collection.find_one({"user_id": user_id})
|
|
|
|
| 181 |
)
|
| 182 |
|
| 183 |
# Generate user ID
|
| 184 |
+
# user_id = f"usr_{secrets.token_urlsafe(16)}"
|
| 185 |
+
user_id=str(uuid.uuid4())
|
| 186 |
# Hash password
|
| 187 |
password_hash = self.get_password_hash(user_data.password)
|
| 188 |
|
|
|
|
| 196 |
|
| 197 |
# Create user model
|
| 198 |
user_model = SystemUserModel(
|
| 199 |
+
user_id=str(user_id),
|
| 200 |
username=user_data.username.lower(),
|
| 201 |
email=user_data.email.lower(),
|
| 202 |
merchant_id=user_data.merchant_id,
|
|
|
|
| 208 |
role=user_data.role,
|
| 209 |
permissions=user_data.permissions,
|
| 210 |
status=UserStatus.ACTIVE, # Set as active by default
|
| 211 |
+
created_by=str(created_by),
|
| 212 |
created_at=datetime.utcnow()
|
| 213 |
)
|
| 214 |
+
doc = user_model.model_dump(by_alias=True, exclude_none=True)
|
| 215 |
+
|
| 216 |
+
# safety: convert UUID -> str if any slips through
|
| 217 |
+
for k, v in doc.items():
|
| 218 |
+
if isinstance(v, uuid.UUID):
|
| 219 |
+
doc[k] = str(v)
|
| 220 |
+
|
| 221 |
+
await self.collection.insert_one(doc)
|
| 222 |
|
| 223 |
logger.info(f"User created successfully: {user_id}")
|
| 224 |
return user_model
|
|
|
|
| 477 |
"warning_threshold_days": warning_threshold
|
| 478 |
}
|
| 479 |
|
| 480 |
+
async def mark_password_change_required(self, user_id: UUID, reason: str = "password_rotation") -> bool:
|
| 481 |
"""
|
| 482 |
Mark that a user must change their password.
|
| 483 |
|
|
|
|
| 526 |
logger.error(f"Error marking password change required for {user_id}: {e}")
|
| 527 |
return False
|
| 528 |
|
| 529 |
+
async def record_password_change(self, user_id: UUID, changed_by: str = "user") -> bool:
|
| 530 |
"""
|
| 531 |
Record password change for rotation policy compliance.
|
| 532 |
|
|
|
|
| 600 |
logger.error(f"Error updating user {user_id}: {e}")
|
| 601 |
return None
|
| 602 |
|
| 603 |
+
async def change_password(self, user_id: UUID, current_password: str, new_password: str) -> bool:
|
| 604 |
"""Change user password."""
|
| 605 |
try:
|
| 606 |
user = await self.get_user_by_id(user_id)
|