Skip to content

Commit

Permalink
Merge branch 'hikka-io:main' into docker-uvicorn
Browse files Browse the repository at this point in the history
  • Loading branch information
nitekot authored Aug 29, 2024
2 parents 606c147 + 016776a commit caea4a4
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 11 deletions.
53 changes: 50 additions & 3 deletions app/client/schemas.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pydantic import Field, HttpUrl
from pydantic import Field, HttpUrl, field_validator

from app.schemas import CustomModel, ClientResponse, PaginationResponse
from app import constants, utils


class ClientFullResponse(ClientResponse):
Expand All @@ -15,31 +16,77 @@ class ClientPaginationResponse(CustomModel):

class ClientCreate(CustomModel):
name: str = Field(
examples=["ThirdPartyWatchlistImporter"], description="Client name"
examples=["ThirdPartyWatchlistImporter"],
description="Client name",
min_length=3,
max_length=constants.MAX_CLIENT_NAME_LENGTH,
)
description: str = Field(
examples=["Client that imports watchlist from third-party services"],
description="Short clear description of the client",
min_length=3,
max_length=constants.MAX_CLIENT_DESCRIPTION_LENGTH,
)
endpoint: HttpUrl = Field(
examples=["https://example.com", "http://localhost/auth/confirm"],
description="Endpoint of the client. "
"User will be redirected to that endpoint after successful "
"authorization",
max_length=constants.MAX_CLIENT_ENDPOINT_LENGTH,
)

@field_validator("name", "description", mode="before")
def validate_name(cls, v: str) -> str:
if not isinstance(v, str):
return v

return utils.remove_bad_characters(v).strip()

@field_validator("endpoint")
def validate_endpoint(cls, v: HttpUrl) -> HttpUrl:
if len(str(v)) > constants.MAX_CLIENT_ENDPOINT_LENGTH:
raise ValueError(
f"Endpoint length should be less than {constants.MAX_CLIENT_ENDPOINT_LENGTH}"
)

return v


class ClientUpdate(CustomModel):
name: str | None = Field(
None,
description="Client name",
max_length=constants.MAX_CLIENT_NAME_LENGTH,
min_length=3,
)
description: str | None = Field(
None,
description="Short clear description of the client",
max_length=constants.MAX_CLIENT_DESCRIPTION_LENGTH,
min_length=3,
)
endpoint: HttpUrl | None = Field(
None,
description="Endpoint of the client",
max_length=constants.MAX_CLIENT_ENDPOINT_LENGTH,
)
endpoint: HttpUrl | None = Field(None, description="Endpoint of the client")
revoke_secret: bool = Field(
False,
description="Create new client secret and revoke previous",
)

@field_validator("name", "description", mode="before")
def validate_name(cls, v: str) -> str:
if not isinstance(v, str):
return v

return utils.remove_bad_characters(v).strip()

@field_validator("endpoint")
def validate_endpoint(cls, v: HttpUrl | None) -> HttpUrl | None:
if len(str(v)) > constants.MAX_CLIENT_ENDPOINT_LENGTH:
raise ValueError(
f"Endpoint length should be less than {constants.MAX_CLIENT_ENDPOINT_LENGTH}"
)

return v
8 changes: 6 additions & 2 deletions app/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@

MAX_USER_CLIENTS = 10

MAX_CLIENT_NAME_LENGTH = 128
MAX_CLIENT_DESCRIPTION_LENGTH = 512
MAX_CLIENT_ENDPOINT_LENGTH = 128

# Meilisearch index names
SEARCH_INDEX_CHARACTERS = "content_characters"
SEARCH_INDEX_COMPANIES = "content_companies"
Expand Down Expand Up @@ -316,7 +320,7 @@
ROLE_USER = "user"
ROLE_MODERATOR = "moderator"
ROLE_ADMIN = "admin"
ROLE_BANNED = "banned"
ROLE_RESTRICTED = "restricted"
ROLE_NOT_ACTIVATED = "not_activated"
ROLE_DELETED = "deleted"

Expand Down Expand Up @@ -390,7 +394,7 @@
PERMISSION_UPLOAD_AVATAR,
PERMISSION_UPLOAD_COVER,
],
ROLE_BANNED: [],
ROLE_RESTRICTED: [],
ROLE_DELETED: [],
}

Expand Down
81 changes: 81 additions & 0 deletions tests/client/test_client_create.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from starlette import status

from tests.client_requests import request_client_create
from app import constants


async def test_client_create(client, test_token, test_user):
Expand Down Expand Up @@ -51,3 +52,83 @@ async def test_client_create_double(client, test_token):
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["code"] == "client:already_exists"


async def test_too_long_fields(client, test_token):
error_message_format = "Invalid field {field} in request body"
error_code = "system:validation_error"

response = await request_client_create(
client,
test_token,
"a" * (constants.MAX_CLIENT_NAME_LENGTH + 1),
"description",
"http://localhost/",
)

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="name"
)

response = await request_client_create(
client,
test_token,
"name",
"a" * (constants.MAX_CLIENT_DESCRIPTION_LENGTH + 1),
"http://localhost/",
)

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="description"
)

response = await request_client_create(
client,
test_token,
"name",
"description",
"http://localhost/" + "a" * (constants.MAX_CLIENT_ENDPOINT_LENGTH + 1),
)

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="endpoint"
)


async def test_too_short_fields(client, test_token):
error_message_format = "Invalid field {field} in request body"
error_code = "system:validation_error"

response = await request_client_create(
client,
test_token,
"a",
"description",
"http://localhost/",
)
assert response.status_code == status.HTTP_400_BAD_REQUEST

assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="name"
)

response = await request_client_create(
client,
test_token,
"name",
"a",
"http://localhost/",
)
assert response.status_code == status.HTTP_400_BAD_REQUEST

assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="description"
)
93 changes: 93 additions & 0 deletions tests/client/test_client_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from starlette import status

from tests.client_requests import request_client_create, request_client_update
from app import constants


async def test_client_update(client, test_token):
Expand Down Expand Up @@ -52,3 +53,95 @@ async def test_client_update_nonexistent(client, test_token):
assert response.status_code == status.HTTP_404_NOT_FOUND

assert response.json()["code"] == "client:not_found"


async def test_too_long_fields(client, test_token):
error_message_format = "Invalid field {field} in request body"
error_code = "system:validation_error"

name = "test-client"
description = "test client description"
endpoint = "http://localhost/"

response = await request_client_create(
client, test_token, name, description, endpoint
)
assert response.status_code == status.HTTP_200_OK

client_reference = response.json()["reference"]

response = await request_client_update(
client,
test_token,
client_reference,
name="a" * (constants.MAX_CLIENT_NAME_LENGTH + 1),
)

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="name"
)

response = await request_client_update(
client,
test_token,
client_reference,
description="a" * (constants.MAX_CLIENT_DESCRIPTION_LENGTH + 1),
)

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="description"
)

response = await request_client_update(
client,
test_token,
client_reference,
endpoint="http://localhost/"
+ "a" * (constants.MAX_CLIENT_ENDPOINT_LENGTH + 1),
)

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="endpoint"
)


async def test_too_short_fields(client, test_token):
error_message_format = "Invalid field {field} in request body"
error_code = "system:validation_error"

name = "test-client"
description = "test client description"
endpoint = "http://localhost/"

response = await request_client_create(
client, test_token, name, description, endpoint
)
assert response.status_code == status.HTTP_200_OK

client_reference = response.json()["reference"]

response = await request_client_update(
client, test_token, client_reference, name="a"
)
assert response.status_code == status.HTTP_400_BAD_REQUEST

assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="name"
)

response = await request_client_update(
client, test_token, client_reference, description="a"
)
assert response.status_code == status.HTTP_400_BAD_REQUEST

assert response.json()["code"] == error_code
assert response.json()["message"] == error_message_format.format(
field="description"
)
15 changes: 15 additions & 0 deletions tests/comments/test_comments_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,18 @@ async def test_comments_write_empty_markdown(

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["code"] == "system:validation_error"


async def test_comments_write_bad_permission(
client,
aggregator_anime,
aggregator_anime_info,
create_dummy_user_restricted,
get_dummy_token,
):
response = await request_comments_write(
client, get_dummy_token, "edit", "17", "First comment, yay!"
)

assert response.status_code == status.HTTP_403_FORBIDDEN
assert response.json()["code"] == "permission:denied"
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,12 @@ async def create_dummy_user(test_session):


@pytest.fixture
async def create_dummy_user_banned(test_session):
async def create_dummy_user_restricted(test_session):
return await helpers.create_user(
test_session,
username="dummy",
email="[email protected]",
role=constants.ROLE_BANNED,
role=constants.ROLE_RESTRICTED,
)


Expand Down
2 changes: 1 addition & 1 deletion tests/edit/test_edit_close.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ async def test_edit_close_bad_permission(
aggregator_anime,
aggregator_anime_info,
create_test_user,
create_dummy_user_banned,
create_dummy_user_restricted,
get_test_token,
get_dummy_token,
test_session,
Expand Down
2 changes: 1 addition & 1 deletion tests/edit/test_edit_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ async def test_edit_create_bad_permission(
client,
aggregator_anime,
aggregator_anime_info,
create_dummy_user_banned,
create_dummy_user_restricted,
get_dummy_token,
test_session,
):
Expand Down
2 changes: 1 addition & 1 deletion tests/upload/test_upload_avatar.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async def test_upload_avatar(

async def test_upload_avatar_bad_permission(
client,
create_dummy_user_banned,
create_dummy_user_restricted,
get_dummy_token,
mock_s3_upload_file,
):
Expand Down
2 changes: 1 addition & 1 deletion tests/upload/test_upload_cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async def test_upload_cover(

async def test_upload_cover_bad_permission(
client,
create_dummy_user_banned,
create_dummy_user_restricted,
get_dummy_token,
mock_s3_upload_file,
):
Expand Down

0 comments on commit caea4a4

Please sign in to comment.