Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Host, Panelist and Scorekeeper Preferred Pronouns and Add Pronouns API Endpoints #68

Merged
merged 6 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changes

## 2.10.0

### Application Changes

- Starting with application version 2.10.0 of the Stats API, the minimum required version of the Wait Wait Stats Database is 4.7
- Change the `pronouns` property for Hosts, Panelists and Scorekeepers from returning a string to a list of pronouns
- Add `Pronouns` and `PronounsInfoList` models
- Add new Pronouns endpoints to retrieve all available pronouns or individual pronouns values

## 2.9.1.post1

**Note:** The `APP_VERSION` was not correctly incremented with version 2.9.1 and has been corrected with this release.
Expand Down
2 changes: 1 addition & 1 deletion INSTALLING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# INSTALLING

The following instructions target Ubuntu 20.04 LTS and Ubuntu 22.04 LTS; but, with some minor changes, should also apply to Linux distribution that uses `systemd` to manage services. Python 3.10 or newer is required and the system must already have a working installation available.
The following instructions target Debian 12 and Ubuntu 22.04 LTS; but, with some minor changes, should also apply to Linux distribution that uses `systemd` to manage services. Python 3.10 or newer is required and the system must already have a working installation available.

This document provides instructions on how to serve the application through [Gunicorn](https://gunicorn.org) and use [NGINX](https://nginx.org/) as a front-end HTTP server. Other options are available for serving up FastAPI applications, but those options will not be covered here.

Expand Down
2 changes: 1 addition & 1 deletion app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from typing import Any

API_VERSION = "2.0"
APP_VERSION = "2.9.1.post1"
APP_VERSION = "2.10.0"


def load_config(
Expand Down
2 changes: 2 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
hosts,
locations,
panelists,
pronouns,
scorekeepers,
shows,
version,
Expand Down Expand Up @@ -139,6 +140,7 @@ async def api_v1_docs_redirect():
app.include_router(hosts.router)
app.include_router(locations.router)
app.include_router(panelists.router)
app.include_router(pronouns.router)
app.include_router(scorekeepers.router)
app.include_router(shows.router)
app.include_router(version.router)
4 changes: 4 additions & 0 deletions app/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@
"name": "Panelists",
"description": "Retrieve information, statistics and appearances for Panelists",
},
{
"name": "Pronouns",
"description": "Retrieve information, statistics and appearances for Pronouns",
},
{
"name": "Scorekeepers",
"description": "Retrieve information and appearances for Scorekeepers",
Expand Down
2 changes: 1 addition & 1 deletion app/models/hosts.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Host(BaseModel):
name: str = Field(title="Host Name")
slug: str | None = Field(default=None, title="Host Slug String")
gender: str | None = Field(default=None, title="Host Gender")
pronouns: str | None = Field(default=None, title="Host Pronouns")
pronouns: list[str] | None = Field(default=None, title="Host Preferred Pronouns")


class Hosts(BaseModel):
Expand Down
4 changes: 3 additions & 1 deletion app/models/panelists.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ class Panelist(BaseModel):
name: str = Field(title="Panelist Name")
slug: str | None = Field(default=None, title="Panelist Slug String")
gender: str | None = Field(default=None, title="Panelist Gender")
pronouns: str | None = Field(default=None, title="Panelist Pronouns")
pronouns: list[str] | None = Field(
default=None, title="Panelist Preferred Pronouns"
)


class Panelists(BaseModel):
Expand Down
23 changes: 23 additions & 0 deletions app/models/pronouns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) 2018-2024 Linh Pham
# api.wwdt.me is released under the terms of the Apache License 2.0
# SPDX-License-Identifier: Apache-2.0
#
# vim: set noai syntax=python ts=4 sw=4:
"""Pronouns Models."""

from typing import Annotated

from pydantic import BaseModel, Field


class Pronouns(BaseModel):
"""Pronouns Information."""

id: Annotated[int, Field(ge=0, lt=2**31)] = Field(title="Pronouns ID")
pronouns: str = Field(title="Pronouns")


class PronounsInfoList(BaseModel):
"""List containing Pronouns Information."""

pronouns: list[Pronouns] = Field(title="List of Pronouns")
4 changes: 3 additions & 1 deletion app/models/scorekeepers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ class Scorekeeper(BaseModel):
name: str = Field(title="Scorekeeper Name")
slug: str | None = Field(default=None, title="Scorekeeper Slug String")
gender: str | None = Field(default=None, title="Scorekeeper Gender")
pronouns: str | None = Field(default=None, title="Scorekeeper Pronouns")
pronouns: list[str] | None = Field(
default=None, title="Scorekeeper Preferred Pronouns"
)


class Scorekeepers(BaseModel):
Expand Down
94 changes: 94 additions & 0 deletions app/routers/pronouns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Copyright (c) 2018-2024 Linh Pham
# api.wwdt.me is released under the terms of the Apache License 2.0
# SPDX-License-Identifier: Apache-2.0
#
# vim: set noai syntax=python ts=4 sw=4:
"""API routes for Pronouns endpoints."""

from typing import Annotated

import mysql.connector
from fastapi import APIRouter, HTTPException, Path
from mysql.connector.errors import DatabaseError, ProgrammingError
from wwdtm.pronoun import Pronouns

from app.config import API_VERSION, load_config
from app.models.pronouns import Pronouns as ModelsPronouns
from app.models.pronouns import PronounsInfoList as ModelsPronounsInfoList

router = APIRouter(prefix=f"/v{API_VERSION}/pronouns")
_config = load_config()
_database_config = _config["database"]
_database_connection = mysql.connector.connect(**_database_config)


@router.get(
"",
summary="Retrieve Information for All Pronouns",
response_model=ModelsPronounsInfoList,
tags=["Pronouns"],
)
@router.head("", include_in_schema=False)
async def get_pronouns():
"""Retrieve All Pronouns.

Returned data: Pronouns ID and pronouns string

Values are sorted by Pronouns ID.
"""
try:
_pronouns = Pronouns(database_connection=_database_connection)
all_pronouns = _pronouns.retrieve_all()
if not all_pronouns:
raise HTTPException(status_code=404, detail="No pronouns found")
else:
return {"pronouns": all_pronouns}
except ProgrammingError:
raise HTTPException(
status_code=500, detail="Unable to retrieve pronouns from the database"
) from None
except DatabaseError:
raise HTTPException(
status_code=500,
detail="Database error occurred while retrieving pronouns from the database",
) from None


@router.get(
"/id/{pronouns_id}",
summary="Retrieve Information by Pronouns ID",
response_model=ModelsPronouns,
tags=["Pronouns"],
)
@router.head("/id/{pronouns_id}", include_in_schema=False)
async def get_pronouns_by_id(
pronouns_id: Annotated[
int, Path(title="The ID of the pronouns to get", ge=0, lt=2**31)
]
):
"""Retrieve a Pronouns String by Pronouns ID.

Returned data: Pronouns ID and pronouns string
"""
try:
_pronouns = Pronouns(database_connection=_database_connection)
pronouns_info = _pronouns.retrieve_by_id(pronouns_id)
if not pronouns_info:
raise HTTPException(
status_code=404, detail=f"Pronouns ID {pronouns_id} not found"
)
else:
return pronouns_info
except ValueError:
raise HTTPException(
status_code=404, detail=f"Pronouns ID {pronouns_id} not found"
) from None
except ProgrammingError:
raise HTTPException(
status_code=500, detail="Unable to retrieve pronouns information"
) from None
except DatabaseError:
raise HTTPException(
status_code=500,
detail="Database error occurred while trying to retrieve pronouns information",
) from None
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ jinja2==3.1.4
email-validator==2.1.0.post1
requests==2.31.0

wwdtm==2.9.1
wwdtm>=2.9.1
37 changes: 37 additions & 0 deletions tests/test_pronouns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright (c) 2018-2024 Linh Pham
# api.wwdt.me is released under the terms of the Apache License 2.0
# SPDX-License-Identifier: Apache-2.0
#
# vim: set noai syntax=python ts=4 sw=4:
"""Testing /v2.0/pronouns routes."""

import pytest
from fastapi.testclient import TestClient

from app.config import API_VERSION
from app.main import app

client = TestClient(app)


def test_pronouns():
"""Test /v2.0/pronouns route."""
response = client.get(f"/v{API_VERSION}/pronouns")
pronouns = response.json()

assert response.status_code == 200
assert "pronouns" in pronouns
assert "id" in pronouns["pronouns"][0]
assert "pronouns" in pronouns["pronouns"][0]


@pytest.mark.parametrize("pronouns_id", [1])
def test_pronouns_id(pronouns_id: int):
"""Test /v2.0/pronouns/id/{pronouns_id} route."""
response = client.get(f"/v{API_VERSION}/pronouns/id/{pronouns_id}")
pronouns_info = response.json()

assert response.status_code == 200
assert "id" in pronouns_info
assert pronouns_info["id"] == pronouns_id
assert "pronouns" in pronouns_info