diff --git a/app/backend/routes/admin.py b/app/backend/routes/admin.py index 54e5a3dfdff7157ab0b0fdf639a438c0b4f1fb35..d2b14c784316327933cb2593da3ecee249606098 100644 --- a/app/backend/routes/admin.py +++ b/app/backend/routes/admin.py @@ -213,14 +213,17 @@ def get_user_statistics( # Count users by creation date user_counts = session.exec( - select(func.date(User.created_at).label("day"), func.count().label("count")) + select( + func.strftime("%Y-%m-%d", User.created_at).label("day"), + func.count().label("count"), + ) .where(User.created_at >= start_date) - .group_by(func.date(User.created_at)) + .group_by(func.strftime("%Y-%m-%d", User.created_at)) ).all() # Update counts for day_data in user_counts: - day_str = day_data[0].strftime("%Y-%m-%d") + day_str = day_data[0] # Now it's already in the correct string format users_by_day[day_str] = day_data[1] # Convert to list of dictionaries diff --git a/app/tests/test_admin.py b/app/tests/test_admin.py new file mode 100644 index 0000000000000000000000000000000000000000..f50f7dcf36332edbe5096c2c817ea0504ca53776 --- /dev/null +++ b/app/tests/test_admin.py @@ -0,0 +1,191 @@ +import pytest +from datetime import datetime, timedelta +from app.backend.models.models import User, Shop, Category, Product, Order, OrderItem +from app.backend.utils.hashing import create_access_token +from sqlmodel import select + + +@pytest.fixture +def admin_token(db_session): + """Create an admin user and return their token""" + admin = User( + username="admin", + email="admin@test.com", + password="hashedpassword", + phone_number="1234567890", + role="admin", + ) + db_session.add(admin) + db_session.commit() + + return create_access_token({"sub": str(admin.id)}) + + +@pytest.fixture +def regular_user_token(db_session): + """Create a regular user and return their token""" + user = User( + username="user", + email="user@test.com", + password="hashedpassword", + phone_number="1234567890", + role="customer", + ) + db_session.add(user) + db_session.commit() + + return create_access_token({"sub": str(user.id)}) + + +@pytest.fixture +def sample_data(db_session): + """Create sample data for testing""" + # Create shop owner + owner = User( + username="owner", + email="owner@test.com", + password="hashedpassword", + phone_number="1234567890", + role="shop_owner", + ) + db_session.add(owner) + db_session.commit() + + # Create shop + shop = Shop( + owner_id=owner.id, + name="Test Shop", + description="Test Description", + address="Test Address", + latitude=0.0, + longitude=0.0, + ) + db_session.add(shop) + db_session.commit() + + return {"owner": owner, "shop": shop} + + +def test_get_all_users_as_admin(client, admin_token): + """Test getting all users as admin""" + response = client.get( + "/admin/users", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 200 + assert isinstance(response.json(), list) + + +def test_get_all_users_as_regular_user(client, regular_user_token): + """Test getting all users as regular user (should fail)""" + response = client.get( + "/admin/users", headers={"Authorization": f"Bearer {regular_user_token}"} + ) + assert response.status_code == 403 + + +def test_get_shop_owners(client, admin_token, sample_data): + """Test getting all shop owners""" + response = client.get( + "/admin/owners", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 200 + owners = response.json() + assert len(owners) > 0 + assert any(owner["email"] == "owner@test.com" for owner in owners) + + +def test_get_specific_shop_owner(client, admin_token, sample_data): + """Test getting a specific shop owner""" + owner_id = sample_data["owner"].id + response = client.get( + f"/admin/owners/{owner_id}", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 200 + assert response.json()["email"] == "owner@test.com" + + +def test_delete_shop_owner(client, admin_token, sample_data): + """Test deleting a shop owner""" + owner_id = sample_data["owner"].id + response = client.delete( + f"/admin/owners/{owner_id}", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 200 + assert response.json()["message"] == "Shop owner deleted successfully" + + +def test_get_user_statistics(client, admin_token, db_session): + """Test getting user statistics""" + # Create some test users with different dates + test_user = User( + username="testuser", + email="test@test.com", + password="hashedpassword", + phone_number="1234567890", + role="customer", + ) + db_session.add(test_user) + db_session.commit() + + response = client.get( + "/admin/stats/users", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 200 + stats = response.json() + assert "total_users" in stats + assert "total_shop_owners" in stats + assert "user_growth" in stats + assert isinstance(stats["user_growth"], list) + + +def test_get_revenue_statistics(client, admin_token): + """Test getting revenue statistics""" + response = client.get( + "/admin/stats/revenue", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 200 + stats = response.json() + assert "total_revenue" in stats + assert "product_revenue" in stats + assert "shipping_revenue" in stats + assert "revenue_over_time" in stats + + +def test_get_product_statistics(client, admin_token): + """Test getting product statistics""" + response = client.get( + "/admin/stats/products", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 200 + stats = response.json() + assert "total_products" in stats + assert "products_by_category" in stats + assert "product_sales" in stats + + +def test_delete_admin_account_fail(client, admin_token, db_session): + """Test that admin cannot delete their own account""" + # Get admin user + admin = db_session.exec(select(User).where(User.email == "admin@test.com")).first() + + response = client.delete( + f"/admin/users/{admin.id}", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 400 + assert "Cannot delete own account" in response.json()["detail"] + + +def test_get_categories(client, admin_token, db_session): + """Test getting all categories""" + # Create a test category + category = Category(name="Test Category") + db_session.add(category) + db_session.commit() + + response = client.get( + "/admin/categories", headers={"Authorization": f"Bearer {admin_token}"} + ) + assert response.status_code == 200 + categories = response.json() + assert len(categories) > 0 + assert any(cat["name"] == "Test Category" for cat in categories)