Skip to content

Commit 937158e

Browse files
authored
add airlines crud (#26)
2 parents 5c8ccaa + 607d406 commit 937158e

File tree

4 files changed

+273
-0
lines changed

4 files changed

+273
-0
lines changed

tests/test_airline.py

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
from flask.testing import FlaskClient
2+
from sqlalchemy.sql import func, select
3+
4+
from teufa import db as dbm
5+
from teufa.ext import db
6+
7+
8+
def test_create_airline(client: FlaskClient, tenant: dbm.Tenant):
9+
response = client.post(
10+
"/api/v1/airlines",
11+
json={
12+
"airline": {
13+
"name": "Test Airline",
14+
"iata": "TA",
15+
"icao": "TST",
16+
}
17+
},
18+
)
19+
20+
assert response.status_code == 201
21+
assert response.json == {
22+
"airline": {
23+
"id": 1,
24+
"name": "Test Airline",
25+
"iata": "TA",
26+
"icao": "TST",
27+
}
28+
}
29+
30+
31+
def test_get_airline(client: FlaskClient, tenant: dbm.Tenant):
32+
airline = dbm.Airline(
33+
tenant_id=tenant.id,
34+
name="Test Airline",
35+
iata="TA",
36+
icao="TST",
37+
)
38+
db.session.add(airline)
39+
db.session.commit()
40+
41+
response = client.get(f"/api/v1/airlines/{airline.id}")
42+
43+
assert response.status_code == 200
44+
assert response.json == {
45+
"airline": {
46+
"id": airline.id,
47+
"name": "Test Airline",
48+
"iata": "TA",
49+
"icao": "TST",
50+
}
51+
}
52+
53+
54+
def test_get_airline_not_found(client: FlaskClient):
55+
response = client.get("/api/v1/airlines/1")
56+
57+
assert response.status_code == 404
58+
assert response.json == {"message": "Airline not found"}
59+
60+
61+
def test_update_airline(client: FlaskClient, tenant: dbm.Tenant):
62+
airline = dbm.Airline(
63+
tenant_id=tenant.id,
64+
name="Test Airline",
65+
iata="TA",
66+
icao="TST",
67+
)
68+
db.session.add(airline)
69+
db.session.commit()
70+
71+
response = client.put(
72+
f"/api/v1/airlines/{airline.id}",
73+
json={
74+
"airline": {
75+
"name": "Updated Airline",
76+
"iata": "UA",
77+
"icao": "UPD",
78+
}
79+
},
80+
)
81+
82+
assert response.status_code == 200
83+
assert response.json == {
84+
"airline": {
85+
"id": airline.id,
86+
"name": "Updated Airline",
87+
"iata": "UA",
88+
"icao": "UPD",
89+
}
90+
}
91+
92+
93+
def test_update_airline_not_found(client: FlaskClient):
94+
response = client.put(
95+
"/api/v1/airlines/1",
96+
json={
97+
"airline": {
98+
"name": "Updated Airline",
99+
"iata": "UA",
100+
"icao": "UPD",
101+
}
102+
},
103+
)
104+
105+
assert response.status_code == 404
106+
assert response.json == {"message": "Airline not found"}
107+
108+
109+
def test_delete_airline(client: FlaskClient, tenant: dbm.Tenant):
110+
airline = dbm.Airline(
111+
tenant_id=tenant.id,
112+
name="Test Airline",
113+
iata="TA",
114+
icao="TST",
115+
)
116+
db.session.add(airline)
117+
db.session.commit()
118+
119+
response = client.delete(f"/api/v1/airlines/{airline.id}")
120+
121+
assert response.status_code == 204
122+
assert response.data == b""
123+
124+
with db.session.begin():
125+
assert db.session.scalar(select(func.count(dbm.Airline.id))) == 0
126+
127+
128+
def test_delete_airline_not_found(client: FlaskClient):
129+
response = client.delete("/api/v1/airlines/1")
130+
131+
assert response.status_code == 404
132+
assert response.json == {"message": "Airline not found"}

teufa/dao.py

+36
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from datetime import datetime
2+
13
from pydantic import BaseModel
24

35
empty = object()
@@ -71,3 +73,37 @@ class UpdateFlightResponse(BaseModel):
7173

7274
class GetFlightResponse(BaseModel):
7375
flight: Flight
76+
77+
78+
class Airline(BaseModel):
79+
id: int | None = None
80+
name: str
81+
iata: str
82+
icao: str
83+
84+
85+
class PartialAirline(BaseModel):
86+
id: int | object = empty
87+
name: str | object = empty
88+
iata: str | object = empty
89+
icao: str | object = empty
90+
91+
92+
class CreateAirlineRequest(BaseModel):
93+
airline: Airline
94+
95+
96+
class CreateAirlineResponse(BaseModel):
97+
airline: Airline
98+
99+
100+
class UpdateAirlineRequest(BaseModel):
101+
airline: PartialAirline
102+
103+
104+
class UpdateAirlineResponse(BaseModel):
105+
airline: Airline
106+
107+
108+
class GetAirlineResponse(BaseModel):
109+
airline: Airline

teufa/v1_api/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from .. import db as dbm
55
from ..ext import db
6+
from .airlines import bp as airlines_bp
67
from .flights import bp as flights_bp
78
from .tenants import bp as tenants_bp
89

@@ -25,5 +26,6 @@ def before_request():
2526
).first()
2627

2728

29+
api_bp.register_blueprint(airlines_bp)
2830
api_bp.register_blueprint(flights_bp)
2931
v1_bp.register_blueprint(api_bp)

teufa/v1_api/airlines.py

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
from flask import Blueprint, g, jsonify, request
2+
3+
from .. import dao
4+
from .. import db as dbm
5+
from ..ext import db
6+
7+
bp = Blueprint("airlines", __name__, url_prefix="/airlines")
8+
9+
10+
@bp.route("", methods=["POST"])
11+
def create_airline():
12+
data = request.get_json()
13+
req = dao.CreateAirlineRequest(**data)
14+
15+
airline = dbm.Airline(
16+
tenant_id=g.tenant.id,
17+
name=req.airline.name,
18+
iata=req.airline.iata,
19+
icao=req.airline.icao,
20+
)
21+
22+
db.session.add(airline)
23+
db.session.commit()
24+
25+
res = dao.CreateAirlineResponse(
26+
**{
27+
"airline": {
28+
"id": airline.id,
29+
"name": airline.name,
30+
"iata": airline.iata,
31+
"icao": airline.icao,
32+
}
33+
}
34+
)
35+
36+
return jsonify(res.model_dump()), 201
37+
38+
39+
@bp.route("/<int:airline_id>", methods=["GET"])
40+
def get_airline(airline_id):
41+
airline = db.session.get(dbm.Airline, airline_id)
42+
43+
if not airline:
44+
return jsonify(dao.Error(message="Airline not found").model_dump()), 404
45+
46+
res = dao.GetAirlineResponse(
47+
**{
48+
"airline": {
49+
"id": airline.id,
50+
"name": airline.name,
51+
"iata": airline.iata,
52+
"icao": airline.icao,
53+
}
54+
}
55+
)
56+
57+
return jsonify(res.model_dump())
58+
59+
60+
@bp.route("/<int:airline_id>", methods=["PUT"])
61+
def update_airline(airline_id):
62+
airline = db.session.get(dbm.Airline, airline_id)
63+
64+
if not airline:
65+
return jsonify(dao.Error(message="Airline not found").model_dump()), 404
66+
67+
data = request.get_json()
68+
req = dao.UpdateAirlineRequest(**data)
69+
70+
if req.airline.name is not dao.empty:
71+
airline.name = req.airline.name
72+
if req.airline.iata is not dao.empty:
73+
airline.iata = req.airline.iata
74+
if req.airline.icao is not dao.empty:
75+
airline.icao = req.airline.icao
76+
77+
db.session.commit()
78+
79+
res = dao.UpdateAirlineResponse(
80+
**{
81+
"airline": {
82+
"id": airline.id,
83+
"name": airline.name,
84+
"iata": airline.iata,
85+
"icao": airline.icao,
86+
}
87+
}
88+
)
89+
90+
return jsonify(res.model_dump())
91+
92+
93+
@bp.route("/<int:airline_id>", methods=["DELETE"])
94+
def delete_airline(airline_id):
95+
airline = db.session.get(dbm.Airline, airline_id)
96+
97+
if not airline:
98+
return jsonify(dao.Error(message="Airline not found").model_dump()), 404
99+
100+
db.session.delete(airline)
101+
db.session.commit()
102+
103+
return "", 204

0 commit comments

Comments
 (0)