Skip to content

Commit 2ca1c36

Browse files
authored
Merge pull request #49 from PythonFloripa/feature/#41
Feature/#41
2 parents e234b98 + bdb9ab9 commit 2ca1c36

File tree

8 files changed

+225
-38
lines changed

8 files changed

+225
-38
lines changed

app/enums.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from enum import Enum
2+
3+
4+
class LibraryTagUpdatesEnum(str, Enum):
5+
UPDATE = "updates"
6+
BUG_FIX = "bug_fix"
7+
NEW_FEATURE = "new_feature"
8+
SECURITY_FIX = "security_fix"

app/routers/libraries/routes.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
from typing import List
2+
13
from fastapi import APIRouter, HTTPException, Request, status
24
from pydantic import BaseModel
35

46
from app.schemas import Library as LibrarySchema
7+
from app.schemas import LibraryNews
58
from app.schemas import Subscription as SubscriptionSchema
69
from app.services.database.models import Library, Subscription
710
from app.services.database.orm.library import (
11+
get_libraries_by_language,
812
get_library_ids_by_multiple_names,
913
insert_library,
1014
)
@@ -22,6 +26,36 @@ class SubscribeLibraryResponse(BaseModel):
2226
def setup():
2327
router = APIRouter(prefix="/libraries", tags=["libraries"])
2428

29+
@router.get(
30+
"",
31+
response_model=List[LibrarySchema],
32+
status_code=status.HTTP_200_OK,
33+
summary="Get libraries by language",
34+
description="Get libraries by language",
35+
)
36+
async def get_by_language(request: Request, language: str):
37+
libraryList = await get_libraries_by_language(
38+
language=language, session=request.app.db_session_factory
39+
)
40+
return [
41+
LibrarySchema(
42+
library_name=libraryDb.library_name,
43+
news=[
44+
LibraryNews(
45+
tag=news["tag"], description=news["description"]
46+
)
47+
for news in libraryDb.news
48+
],
49+
logo=libraryDb.logo,
50+
version=libraryDb.version,
51+
release_date=libraryDb.release_date,
52+
releases_doc_url=libraryDb.releases_doc_url,
53+
fixed_release_url=libraryDb.fixed_release_url,
54+
language=libraryDb.language,
55+
)
56+
for libraryDb in libraryList
57+
]
58+
2559
@router.post(
2660
"",
2761
response_model=LibraryResponse,
@@ -35,9 +69,13 @@ async def create_library(
3569
):
3670
library = Library(
3771
library_name=body.library_name,
38-
user_email="", # TODO: Considerar obter o email do usuário autenticado
39-
releases_url=body.releases_url.encoded_string(),
40-
logo=body.logo.encoded_string(),
72+
news=[news.model_dump() for news in body.news],
73+
logo=body.logo,
74+
version=body.version,
75+
release_date=body.release_date,
76+
releases_doc_url=body.releases_doc_url,
77+
fixed_release_url=body.fixed_release_url,
78+
language=body.language,
4179
)
4280
try:
4381
await insert_library(library, request.app.db_session_factory)

app/schemas.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1-
from enum import Enum
1+
from datetime import date
22
from typing import List
33

4-
from pydantic import BaseModel, HttpUrl
4+
from pydantic import BaseModel
5+
6+
from app.enums import LibraryTagUpdatesEnum
7+
8+
9+
class LibraryNews(BaseModel):
10+
tag: LibraryTagUpdatesEnum
11+
description: str
512

613

714
class Library(BaseModel):
15+
id: int | None = None
816
library_name: str
9-
releases_url: HttpUrl
10-
logo: HttpUrl
17+
news: List[LibraryNews]
18+
logo: str
19+
version: str
20+
release_date: date
21+
releases_doc_url: str
22+
fixed_release_url: str
23+
language: str
1124

1225

1326
# Community / User Class
@@ -41,15 +54,7 @@ class TokenPayload(BaseModel):
4154
username: str
4255

4356

44-
# Subscription Class
45-
class SubscriptionTagEnum(str, Enum):
46-
UPDATE = "update"
47-
BUG_FIX = "bug_fix"
48-
NEW_FEATURE = "new_feature"
49-
SECURITY_FIX = "security_fix"
50-
51-
5257
class Subscription(BaseModel):
5358
email: str
54-
tags: List[SubscriptionTagEnum]
59+
tags: List[LibraryTagUpdatesEnum]
5560
libraries_list: List[str]
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
from typing import Optional
1+
from datetime import date
2+
from typing import List, Optional
23

4+
from sqlalchemy import JSON, Column
35
from sqlmodel import Field, SQLModel
46

57

@@ -8,9 +10,13 @@ class Library(SQLModel, table=True):
810

911
id: Optional[int] = Field(default=None, primary_key=True)
1012
library_name: str
11-
user_email: str
12-
releases_url: str
13+
news: List[dict] = Field(sa_column=Column(JSON))
1314
logo: str
15+
version: str
16+
release_date: date
17+
releases_doc_url: str
18+
fixed_release_url: str
19+
language: str
1420
community_id: Optional[int] = Field(
1521
default=None, foreign_key="communities.id"
1622
)

app/services/database/models/subscriptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
from sqlalchemy import JSON, Column
44
from sqlmodel import Field, SQLModel
55

6-
from app.schemas import SubscriptionTagEnum
6+
from app.enums import LibraryTagUpdatesEnum
77

88

99
class Subscription(SQLModel, table=True):
1010
__tablename__ = "subscriptions" # type: ignore
1111

1212
id: Optional[int] = Field(default=None, primary_key=True)
1313
email: str
14-
tags: List[SubscriptionTagEnum] = Field(sa_column=Column(JSON))
14+
tags: List[LibraryTagUpdatesEnum] = Field(sa_column=Column(JSON))
1515
community_id: Optional[int] = Field(
1616
default=None, foreign_key="communities.id"
1717
)

app/services/database/orm/library.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,14 @@ async def get_library_ids_by_multiple_names(
2626
)
2727
result = await session.exec(statement)
2828
return [id for id in result.all() if id is not None]
29+
30+
31+
async def get_libraries_by_language(
32+
language: str,
33+
session: AsyncSession,
34+
) -> List[Library]:
35+
statement = select(Library).where(
36+
func.lower(Library.language) == language.lower()
37+
)
38+
result = await session.exec(statement)
39+
return [library for library in result.all()]

tests/test_libraries.py

Lines changed: 131 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
from datetime import date
2+
13
import pytest
24
import pytest_asyncio
35
from httpx import AsyncClient
46
from sqlmodel import select
57
from sqlmodel.ext.asyncio.session import AsyncSession
68

9+
from app.enums import LibraryTagUpdatesEnum
10+
from app.schemas import LibraryNews
711
from app.services.database.models import Community, Library
812

913

@@ -19,24 +23,38 @@ async def community(session: AsyncSession):
1923
@pytest.mark.asyncio
2024
async def test_insert_libraries(session: AsyncSession, community: Community):
2125
library = Library(
22-
library_name="Python",
23-
user_email="teste@teste.com",
24-
releases_url="http://teste.com",
25-
logo="logo",
26+
library_name="Flask",
27+
news=[
28+
LibraryNews(
29+
tag=LibraryTagUpdatesEnum.UPDATE, description="Updated"
30+
).model_dump(),
31+
LibraryNews(
32+
tag=LibraryTagUpdatesEnum.BUG_FIX, description="Fixed"
33+
).model_dump(),
34+
],
35+
logo="http://teste.com/",
36+
version="3.11",
37+
release_date=date.today(),
38+
releases_doc_url="http://teste.com/",
39+
fixed_release_url="http://teste.com/",
40+
language="Python",
2641
community_id=community.id,
2742
)
2843
session.add(library)
2944
await session.commit()
3045

31-
statement = select(Library).where(Library.library_name == "Python")
46+
statement = select(Library).where(Library.library_name == "Flask")
3247
result = await session.exec(statement)
3348
found = result.first()
3449

3550
assert found is not None
36-
assert found.library_name == "Python"
37-
assert found.user_email == "teste@teste.com"
38-
assert found.releases_url == "http://teste.com"
39-
assert found.logo == "logo"
51+
assert len(found.news) == 2
52+
assert found.logo == "http://teste.com/"
53+
assert found.version == "3.11"
54+
assert found.release_date == date.today()
55+
assert found.releases_doc_url == "http://teste.com/"
56+
assert found.fixed_release_url == "http://teste.com/"
57+
assert found.language == "Python"
4058
assert found.community_id == community.id
4159

4260

@@ -45,9 +63,17 @@ async def test_post_libraries_endpoint(
4563
async_client: AsyncClient, session: AsyncSession
4664
):
4765
body = {
48-
"library_name": "Python from API",
49-
"releases_url": "http://teste.com/",
66+
"library_name": "FastAPI",
67+
"news": [
68+
{"tag": "updates", "description": "Updated"},
69+
{"tag": "bug_fix", "description": "Fixed"},
70+
],
5071
"logo": "http://teste.com/",
72+
"version": "3.11",
73+
"release_date": "2025-01-01",
74+
"releases_doc_url": "http://teste.com/",
75+
"fixed_release_url": "http://teste.com/",
76+
"language": "Python",
5177
}
5278

5379
response = await async_client.post(
@@ -66,5 +92,98 @@ async def test_post_libraries_endpoint(
6692
created_library = result.first()
6793

6894
assert created_library is not None
69-
assert created_library.releases_url == body["releases_url"]
7095
assert created_library.logo == body["logo"]
96+
assert created_library.version == body["version"]
97+
assert created_library.release_date == date.fromisoformat(
98+
body["release_date"]
99+
)
100+
assert created_library.releases_doc_url == body["releases_doc_url"]
101+
assert created_library.fixed_release_url == body["fixed_release_url"]
102+
assert created_library.language == body["language"]
103+
assert len(created_library.news) == len(body["news"])
104+
105+
106+
@pytest.mark.asyncio
107+
async def test_get_libraries_by_language(async_client: AsyncClient):
108+
body = {
109+
"library_name": "FastAPI",
110+
"news": [
111+
{"tag": "updates", "description": "Updated"},
112+
{"tag": "bug_fix", "description": "Fixed"},
113+
],
114+
"logo": "http://teste.com/",
115+
"version": "3.11",
116+
"release_date": "2025-01-01",
117+
"releases_doc_url": "http://teste.com/",
118+
"fixed_release_url": "http://teste.com/",
119+
"language": "Python",
120+
}
121+
122+
responsePOST = await async_client.post(
123+
"/api/libraries",
124+
json=body,
125+
headers={"Content-Type": "application/json"},
126+
)
127+
128+
assert responsePOST.status_code == 200
129+
assert responsePOST.json()["status"] == "Library created successfully"
130+
131+
response = await async_client.get(
132+
"/api/libraries",
133+
params={"language": "Python"},
134+
)
135+
136+
assert response.status_code == 200
137+
138+
data = response.json()
139+
140+
assert len(data) == 1
141+
assert data[0]["library_name"] == "FastAPI"
142+
assert len(data[0]["news"]) == 2
143+
assert data[0]["news"][0]["tag"] == "updates"
144+
assert data[0]["news"][0]["description"] == "Updated"
145+
assert data[0]["news"][1]["tag"] == "bug_fix"
146+
assert data[0]["news"][1]["description"] == "Fixed"
147+
assert data[0]["logo"] == "http://teste.com/"
148+
assert data[0]["version"] == "3.11"
149+
assert data[0]["release_date"] == "2025-01-01"
150+
assert data[0]["releases_doc_url"] == "http://teste.com/"
151+
assert data[0]["fixed_release_url"] == "http://teste.com/"
152+
assert data[0]["language"] == "Python"
153+
154+
155+
@pytest.mark.asyncio
156+
async def test_get_libraries_by_inexistent_language(async_client: AsyncClient):
157+
body = {
158+
"library_name": "FastAPI",
159+
"news": [
160+
{"tag": "updates", "description": "Updated"},
161+
{"tag": "bug_fix", "description": "Fixed"},
162+
],
163+
"logo": "http://teste.com/",
164+
"version": "3.11",
165+
"release_date": "2025-01-01",
166+
"releases_doc_url": "http://teste.com/",
167+
"fixed_release_url": "http://teste.com/",
168+
"language": "Python",
169+
}
170+
171+
responsePOST = await async_client.post(
172+
"/api/libraries",
173+
json=body,
174+
headers={"Content-Type": "application/json"},
175+
)
176+
177+
assert responsePOST.status_code == 200
178+
assert responsePOST.json()["status"] == "Library created successfully"
179+
180+
response = await async_client.get(
181+
"/api/libraries",
182+
params={"language": "NodeJS"},
183+
)
184+
185+
assert response.status_code == 200
186+
187+
data = response.json()
188+
189+
assert len(data) == 0

0 commit comments

Comments
 (0)