diff --git a/main.py b/main.py index e1b496d..05a42ff 100644 --- a/main.py +++ b/main.py @@ -2,9 +2,234 @@ from api.database import Base, engine from api import models from api.routes import router +import requests +from typing import List, Dict, Any # Create tables Base.metadata.create_all(bind=engine) app = FastAPI() app.include_router(router) + +def register_user(base_url, username, password): + """ + Registers a new user with the Polly-API. + + Args: + base_url (str): The base URL of the API (e.g., "http://127.0.0.1:8000"). + username (str): The username for the new user. + password (str): The password for the new user. + + Returns: + requests.Response: The response object from the API call. + """ + url = f"{base_url}/register" + headers = {"Content-Type": "application/json"} + payload = {"username": username, "password": password} + + try: + response = requests.post(url, json=payload, headers=headers) + response.raise_for_status() # Raise an exception for HTTP errors + return response + except requests.exceptions.RequestException as e: + print(f"An error occurred: {e}") + return None + + +def get_paginated_polls(base_url: str, skip: int = 0, limit: int = 10) -> List[Dict[str, Any]] | None: + """ + Fetches paginated poll data from the API. + + Args: + base_url (str): The base URL of the API (e.g., "http://127.0.0.1:8000"). + skip (int): The number of items to skip (for pagination). + limit (int): The maximum number of items to return. + + Returns: + List[Dict[str, Any]] | None: A list of dictionaries representing poll data, or None if an error occurs. + """ + url = f"{base_url}/polls" + params = {"skip": skip, "limit": limit} + + try: + response = requests.get(url, params=params) + response.raise_for_status() # Raise an exception for HTTP errors + return response.json() + except requests.exceptions.RequestException as e: + print(f"An error occurred: {e}") + return None + + +def cast_vote(base_url: str, poll_id: int, option_id: int, access_token: str) -> Dict[str, Any] | None: + """ + Casts a vote on an existing poll. + + Args: + base_url (str): The base URL of the API (e.g., "http://127.0.0.1:8000"). + poll_id (int): The ID of the poll to vote on. + option_id (int): The ID of the option to vote for. + access_token (str): The JWT access token for authentication. + + Returns: + Dict[str, Any] | None: A dictionary representing the vote confirmation, or None if an error occurs. + """ + url = f"{base_url}/polls/{poll_id}/vote" + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {access_token}" + } + payload = {"option_id": option_id} + + try: + response = requests.post(url, json=payload, headers=headers) + response.raise_for_status() # Raise an exception for HTTP errors + return response.json() + except requests.exceptions.RequestException as e: + print(f"An error occurred while casting vote: {e}") + return None + + +def get_poll_results(base_url: str, poll_id: int) -> Dict[str, Any] | None: + """ + Retrieves the results for a specific poll. + + Args: + base_url (str): The base URL of the API (e.g., "http://127.0.0.1:8000"). + poll_id (int): The ID of the poll to retrieve results for. + + Returns: + Dict[str, Any] | None: A dictionary containing the poll results, or None if an error occurs. + """ + url = f"{base_url}/polls/{poll_id}/results" + + try: + response = requests.get(url) + response.raise_for_status() # Raise an exception for HTTP errors + return response.json() + except requests.exceptions.RequestException as e: + print(f"An error occurred while fetching poll results: {e}") + return None + + +def create_poll(base_url: str, question: str, options: List[str], access_token: str) -> Dict[str, Any] | None: + """ + Creates a new poll. + + Args: + base_url (str): The base URL of the API (e.g., "http://127.0.0.1:8000"). + question (str): The question for the poll. + options (List[str]): A list of strings, each representing an option for the poll. + Requires a minimum of two options. + access_token (str): The JWT access token for authentication. + + Returns: + Dict[str, Any] | None: A dictionary representing the created poll, or None if an error occurs. + """ + if len(options) < 2: + print("Error: A poll must have at least two options.") + return None + + url = f"{base_url}/polls" + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {access_token}" + } + payload = {"question": question, "options": options} + + try: + response = requests.post(url, json=payload, headers=headers) + response.raise_for_status() # Raise an exception for HTTP errors + return response.json() + except requests.exceptions.RequestException as e: + print(f"An error occurred while creating poll: {e}") + return None + + +def login_user(base_url: str, username: str, password: str) -> Dict[str, Any] | None: + """ + Logs in a user and retrieves an access token. + + Args: + base_url (str): The base URL of the API (e.g., "http://127.0.0.1:8000"). + username (str): The username of the user. + password (str): The password of the user. + + Returns: + Dict[str, Any] | None: A dictionary containing the access token and token type, + or None if an error occurs. + """ + url = f"{base_url}/login" + headers = {"Content-Type": "application/x-www-form-urlencoded"} # FastAPI expects form data for login + payload = {"username": username, "password": password} + + try: + response = requests.post(url, data=payload, headers=headers) + response.raise_for_status() # Raise an exception for HTTP errors + return response.json() + except requests.exceptions.RequestException as e: + print(f"An error occurred during login: {e}") + return None + + +if __name__ == "__main__": + BASE_URL = "http://127.0.0.1:8000" # Replace with your API's base URL if different + + # --- Authentication and Poll Creation Example --- + USERNAME = "example_user" + PASSWORD = "example_password" + + # 1. Register a user (if not already registered) + print(f"\n--- Registering user: {USERNAME} ---") + register_response = register_user(BASE_URL, USERNAME, PASSWORD) + if register_response and register_response.status_code == 200: + print("User registered successfully.") + elif register_response and register_response.status_code == 409: # 409 Conflict if user already exists + print("User already registered (skipping registration).") + else: + print("User registration failed.") + # Exit if registration failed and we can't proceed + exit() + + # 2. Login the user to get an access token + print(f"\n--- Logging in user: {USERNAME} ---") + login_data = login_user(BASE_URL, USERNAME, PASSWORD) + access_token = None + if login_data and "access_token" in login_data: + access_token = login_data["access_token"] + print("Login successful. Access Token obtained.") + else: + print("Login failed. Cannot proceed with creating polls.") + exit() + + # 3. Create a poll (requires authentication) + if access_token: + print("\n--- Creating a new poll ---") + poll_question = "What's your favorite programming language?" + poll_options = ["Python", "JavaScript", "Java", "C++", "Rust"] + new_poll = create_poll(BASE_URL, poll_question, poll_options, access_token) + + if new_poll: + print("Poll created successfully:") + print(f" Poll ID: {new_poll['id']}") + print(f" Question: {new_poll['question']}") + print(" Options:") + for option in new_poll['options']: + print(f" - {option['text']} (ID: {option['id']})") + else: + print("Failed to create poll.") + else: + print("No access token available. Skipping poll creation.") + + + # --- Previous Poll Results Display Example (uncomment to use) --- + # poll_id_to_display = 1 # Replace with an actual poll_id from your database + # results = get_poll_results(BASE_URL, poll_id_to_display) + + # if results: + # print(f"\n--- Results for Poll ID: {results['poll_id']} ---") + # print(f"Question: {results['question']}") + # print("Options:") + # for option_result in results['results']: + # print(f" - {option_result['text']} (Votes: {option_result['vote_count']})") + # else: + # print(f"Failed to retrieve results for Poll ID {poll_id_to_display}.") diff --git a/requirements.txt b/requirements.txt index c1cb655..13e9484 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,6 @@ sqlalchemy pydantic passlib[bcrypt] jwt -python-dotenv \ No newline at end of file +python-jose +python-dotenv +requests \ No newline at end of file