diff --git a/cli.py b/cli.py index 3bf64bc..4fbb2a3 100644 --- a/cli.py +++ b/cli.py @@ -79,5 +79,14 @@ def clear_location_data(): clear_data_location(db=session, is_commit=True) +@app.command() +def checkin_example_data(): + from models import factory_session + from seeders.initial_checkin_data import initialize_checkin_data + + with factory_session() as session: + initialize_checkin_data(db=session) + + if __name__ == "__main__": app() diff --git a/repository/checkin.py b/repository/checkin.py index cce069f..27ca263 100644 --- a/repository/checkin.py +++ b/repository/checkin.py @@ -1,6 +1,6 @@ import datetime from zoneinfo import ZoneInfo, ZoneInfoNotFoundError - +from uuid import UUID from sqlalchemy import select from sqlalchemy.orm import Session from core.log import logger @@ -21,6 +21,10 @@ def get_user_data_by_payment_id(db: Session, payment_id: str) -> User | None: Returns: User | None: User data or None if not found """ + try: + UUID(payment_id) + except ValueError: + return None query = ( select(User) .join(Payment, Payment.user_id == User.id) diff --git a/repository/speaker.py b/repository/speaker.py index 6971181..9e47f6a 100644 --- a/repository/speaker.py +++ b/repository/speaker.py @@ -11,7 +11,11 @@ from schemas.speaker import SpeakerResponseItem -def get_all_speakers(db: Session, order_dir: Literal["asc", "desc"] = "asc"): +def get_all_speakers( + db: Session, + order_dir: Literal["asc", "desc"] = "asc", + search: Optional[str] = None, +): # Query dasar stmt = select(Speaker) @@ -21,6 +25,15 @@ def get_all_speakers(db: Session, order_dir: Literal["asc", "desc"] = "asc"): else: stmt = stmt.order_by(Speaker.updated_at.desc()) + if search: + search_pattern = f"%{search}%" + stmt = stmt.join(User, Speaker.user).where( + (User.username.ilike(search_pattern)) + | (User.first_name.ilike(search_pattern)) + | (User.last_name.ilike(search_pattern)) + | (User.email.ilike(search_pattern)) + ) + # Tambahkan pagination (offset + limit) # Hitung total data sebelum pagination total_count = db.scalar(select(func.count()).select_from(stmt.subquery())) diff --git a/routes/speaker.py b/routes/speaker.py index 08ba9c7..6d73126 100644 --- a/routes/speaker.py +++ b/routes/speaker.py @@ -60,7 +60,9 @@ async def get_speaker( ): try: if query.all: - data = speakerRepo.get_all_speakers(db=db, order_dir=query.order_dir) + data = speakerRepo.get_all_speakers( + db=db, search=query.search, order_dir=query.order_dir + ) else: data = speakerRepo.get_speaker_per_page_by_search( db=db, diff --git a/routes/tests/test_checkin.py b/routes/tests/test_checkin.py index 5686008..8e20d76 100644 --- a/routes/tests/test_checkin.py +++ b/routes/tests/test_checkin.py @@ -132,7 +132,7 @@ def test_get_user_data_by_payment_id_not_found(self): def test_get_user_data_by_payment_id_invalid(self): """Test response when payment ID format is invalid""" response = self.client.get("/ticket/checkin/invalid-uuid-format") - self.assertIn(response.status_code, [404, 500]) + self.assertEqual(response.status_code, 404) def test_get_user_data_with_no_tshirt_size(self): """Test retrieval when user has no t-shirt size set""" diff --git a/routes/ticket.py b/routes/ticket.py index 3f10c1a..246bf44 100644 --- a/routes/ticket.py +++ b/routes/ticket.py @@ -1,5 +1,4 @@ import traceback - from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import ValidationError from sqlalchemy.orm import Session @@ -25,7 +24,7 @@ from repository.ticket import get_active_tickets from schemas.checkin import ( CheckinUserRequest, - CheckinUserResponse, + CheckinUserResponseSchema, user_model_to_checkin_response, ) from schemas.common import ( @@ -145,7 +144,7 @@ async def get_my_ticket( @router.get( "/checkin/{payment_id}", responses={ - "200": {"model": CheckinUserResponse}, + "200": {"model": CheckinUserResponseSchema}, "404": {"model": NotFoundResponse}, "500": {"model": InternalServerErrorResponse}, }, @@ -192,7 +191,7 @@ async def checkin(payment_id: str, db: Session = Depends(get_db_sync)): @router.patch( "/checkin", responses={ - "200": {"model": CheckinUserResponse}, + "200": {"model": CheckinUserResponseSchema}, "401": {"model": UnauthorizedResponse}, "402": {"model": PaymentRequiredResponse}, "404": {"model": NotFoundResponse}, @@ -259,7 +258,7 @@ async def checkin_user( @router.patch( "/checkin/reset", responses={ - "200": {"model": CheckinUserResponse}, + "200": {"model": CheckinUserResponseSchema}, "401": {"model": UnauthorizedResponse}, "402": {"model": PaymentRequiredResponse}, "404": {"model": NotFoundResponse}, diff --git a/schemas/checkin.py b/schemas/checkin.py index c9a8f92..c2711e0 100644 --- a/schemas/checkin.py +++ b/schemas/checkin.py @@ -17,6 +17,11 @@ class CheckinUserResponse(BaseModel): checked_in_day2: bool = False +class CheckinUserResponseSchema(BaseModel): + data: CheckinUserResponse + message: str = "User check-in data retrieved successfully" + + def user_model_to_checkin_response(user: User) -> CheckinUserResponse: """Convert User model to CheckinUserResponse schema diff --git a/seeders/initial_checkin_data.py b/seeders/initial_checkin_data.py new file mode 100644 index 0000000..dec1e3a --- /dev/null +++ b/seeders/initial_checkin_data.py @@ -0,0 +1,90 @@ +from sqlalchemy.orm import Session +from sqlalchemy import select + + +def initialize_checkin_data( + db: Session, +): + import uuid + + from models.User import User + from models.Ticket import Ticket + from models.Payment import Payment, PaymentStatus + from core.security import generate_hash_password + from core.helper import get_current_time_in_timezone + + ticket_id = uuid.UUID("550e8400-e29b-41d4-a716-446655440000") + payment_id = uuid.UUID("550e8400-e29b-41d4-a716-446655440001") + user_id = uuid.UUID("550e8400-e29b-41d4-a716-446655440002") + + # Check if data already exists + existing_user = db.execute( + select(User).where(User.id == user_id) + ).scalar_one_or_none() + existing_ticket = db.execute( + select(Ticket).where(Ticket.id == ticket_id) + ).scalar_one_or_none() + existing_payment = db.execute( + select(Payment).where(Payment.id == payment_id) + ).scalar_one_or_none() + + if existing_user and existing_ticket and existing_payment: + print("All checkin data already exists. Skipping...") + return + + try: + if not existing_user: + user = User( + id=user_id, + username="checkinuser", + email="checkinuser@example.com", + phone="+628123456789", + first_name="test", + last_name="user", + password=generate_hash_password("password"), + is_active=True, + ) + db.add(user) + else: + user = existing_user + + if not existing_ticket: + ticket = Ticket( + id=ticket_id, + name="Test Conference Ticket", + price=500000, + user_participant_type="In Person", + is_sold_out=False, + is_active=True, + description="Test ticket for payment", + ) + db.add(ticket) + else: + ticket = existing_ticket + + if not existing_payment: + payment = Payment( + id=payment_id, + user_id=user.id, + ticket_id=ticket.id, + payment_link="https://mayar.id/pay/test-link", + status=PaymentStatus.PAID, + created_at=get_current_time_in_timezone(), + mayar_id="mayar-test-id", + mayar_transaction_id="mayar-test-tx", + amount=500000, + description="Test payment", + ) + db.add(payment) + else: + payment = existing_payment + + db.commit() + db.refresh(user) + db.refresh(ticket) + db.refresh(payment) + print("Checkin data initialized successfully!") + except Exception as e: + db.rollback() + print(f"Error initializing checkin data: {e}") + raise